diff options
| author | Adrian Kummerlaender | 2018-12-15 23:09:32 +0100 | 
|---|---|---|
| committer | Adrian Kummerlaender | 2018-12-15 23:09:32 +0100 | 
| commit | 44f5ac32a68a617f93704d44c4339f7db13b323e (patch) | |
| tree | 6c191524aca1c7dbf3329026a59cfa3bc0109d2f /src | |
| download | compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar.gz compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar.bz2 compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar.lz compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar.xz compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.tar.zst compustream-44f5ac32a68a617f93704d44c4339f7db13b323e.zip | |
Hacky D2Q9 BGK LBM on GPU using GLSL compute shaders
Improvised on top of computicles's scaffolding.
Works in a world where _works_ is defined as "displays stuff on screen that invokes thoughts of fluid movement".
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer/vertex/fluid_cell_buffer.cc | 33 | ||||
| -rw-r--r-- | src/buffer/vertex/fluid_cell_buffer.h | 21 | ||||
| -rw-r--r-- | src/buffer/vertex/lattice_cell_buffer.cc | 40 | ||||
| -rw-r--r-- | src/buffer/vertex/lattice_cell_buffer.h | 19 | ||||
| -rw-r--r-- | src/glfw/guard.cc | 16 | ||||
| -rw-r--r-- | src/glfw/guard.h | 11 | ||||
| -rw-r--r-- | src/glfw/key_watcher.cc | 24 | ||||
| -rw-r--r-- | src/glfw/key_watcher.h | 17 | ||||
| -rw-r--r-- | src/glfw/window.cc | 32 | ||||
| -rw-r--r-- | src/glfw/window.h | 58 | ||||
| -rw-r--r-- | src/main.cc | 156 | ||||
| -rw-r--r-- | src/shader/code/collide.glsl | 95 | ||||
| -rw-r--r-- | src/shader/code/fragment.glsl | 5 | ||||
| -rw-r--r-- | src/shader/code/stream.glsl | 30 | ||||
| -rw-r--r-- | src/shader/code/vertex.glsl | 8 | ||||
| -rw-r--r-- | src/shader/util.cc | 56 | ||||
| -rw-r--r-- | src/shader/util.h | 13 | ||||
| -rw-r--r-- | src/shader/wrap/compute_shader.cc | 51 | ||||
| -rw-r--r-- | src/shader/wrap/compute_shader.h | 32 | ||||
| -rw-r--r-- | src/shader/wrap/graphic_shader.cc | 45 | ||||
| -rw-r--r-- | src/shader/wrap/graphic_shader.h | 29 | ||||
| -rw-r--r-- | src/timer.cc | 16 | ||||
| -rw-r--r-- | src/timer.h | 12 | 
23 files changed, 819 insertions, 0 deletions
| diff --git a/src/buffer/vertex/fluid_cell_buffer.cc b/src/buffer/vertex/fluid_cell_buffer.cc new file mode 100644 index 0000000..5056569 --- /dev/null +++ b/src/buffer/vertex/fluid_cell_buffer.cc @@ -0,0 +1,33 @@ +#include "fluid_cell_buffer.h" + +FluidCellBuffer::FluidCellBuffer(): +	_data(3*128*128, GLfloat{}) { +	glGenVertexArrays(1, &_array); +	glGenBuffers(1, &_buffer); + +	glBindVertexArray(_array); +	glBindBuffer(GL_ARRAY_BUFFER, _buffer); +	glBufferData( +		GL_ARRAY_BUFFER, +		_data.size() * sizeof(GLfloat), +		_data.data(), +		GL_DYNAMIC_DRAW +	); + +	glEnableVertexAttribArray(0); +	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); +} + +FluidCellBuffer::~FluidCellBuffer() { +	glDeleteBuffers(1, &_buffer); +	glDeleteVertexArrays(1, &_array); +} + +GLuint FluidCellBuffer::getBuffer() const { +	return _buffer; +} + +void FluidCellBuffer::draw() const { +	glBindVertexArray(_array); +	glDrawArrays(GL_POINTS, 0, _data.size()); +} diff --git a/src/buffer/vertex/fluid_cell_buffer.h b/src/buffer/vertex/fluid_cell_buffer.h new file mode 100644 index 0000000..b2b880a --- /dev/null +++ b/src/buffer/vertex/fluid_cell_buffer.h @@ -0,0 +1,21 @@ +#pragma once + +#include <vector> + +#include <GL/glew.h> + +class FluidCellBuffer { +private: +	std::vector<GLfloat> _data; + +	GLuint _array; +	GLuint _buffer; + +public: +	FluidCellBuffer(); +	~FluidCellBuffer(); + +	GLuint getBuffer() const; + +	void draw() const; +}; diff --git a/src/buffer/vertex/lattice_cell_buffer.cc b/src/buffer/vertex/lattice_cell_buffer.cc new file mode 100644 index 0000000..7fb51d8 --- /dev/null +++ b/src/buffer/vertex/lattice_cell_buffer.cc @@ -0,0 +1,40 @@ +#include "lattice_cell_buffer.h" + +#include <fstream> + +LatticeCellBuffer::LatticeCellBuffer(): +	_data(9*128*128, GLfloat{1./9.}) { +	glGenVertexArrays(1, &_array); +	glGenBuffers(1, &_buffer); + +	for (int x = 50; x < 128-50; x++) { +		for (int y = 50; y < 128-50; y++) { +			for ( int i = -1; i <= 1; ++i ) { +				for ( int j = -1; j <= 1; ++j ) { +					_data[9*128*y + 9*x + (i+1)*3 + j+1] = 1./128.; +				} +			} +		} +	} + +	glBindVertexArray(_array); +	glBindBuffer(GL_ARRAY_BUFFER, _buffer); +	glBufferData( +		GL_ARRAY_BUFFER, +		_data.size() * sizeof(GLfloat), +		_data.data(), +		GL_DYNAMIC_DRAW +	); + +	glEnableVertexAttribArray(0); +	glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr); +} + +LatticeCellBuffer::~LatticeCellBuffer() { +	glDeleteBuffers(1, &_buffer); +	glDeleteVertexArrays(1, &_array); +} + +GLuint LatticeCellBuffer::getBuffer() const { +	return _buffer; +} diff --git a/src/buffer/vertex/lattice_cell_buffer.h b/src/buffer/vertex/lattice_cell_buffer.h new file mode 100644 index 0000000..c28319e --- /dev/null +++ b/src/buffer/vertex/lattice_cell_buffer.h @@ -0,0 +1,19 @@ +#pragma once + +#include <vector> + +#include <GL/glew.h> + +class LatticeCellBuffer { +private: +	std::vector<GLfloat> _data; + +	GLuint _array; +	GLuint _buffer; + +public: +	LatticeCellBuffer(); +	~LatticeCellBuffer(); + +	GLuint getBuffer() const; +}; diff --git a/src/glfw/guard.cc b/src/glfw/guard.cc new file mode 100644 index 0000000..5ba853f --- /dev/null +++ b/src/glfw/guard.cc @@ -0,0 +1,16 @@ +#include "guard.h" + +#include <GL/glew.h> +#include <GLFW/glfw3.h> + +GlfwGuard::GlfwGuard() { +	_good = glfwInit(); +} + +GlfwGuard::~GlfwGuard() { +	glfwTerminate(); +} + +bool GlfwGuard::isGood() const { +	return _good; +} diff --git a/src/glfw/guard.h b/src/glfw/guard.h new file mode 100644 index 0000000..f68954d --- /dev/null +++ b/src/glfw/guard.h @@ -0,0 +1,11 @@ +#pragma once + +class GlfwGuard { +private: +	bool _good = false; +public: +	GlfwGuard(); +	~GlfwGuard(); + +	bool isGood() const; +}; diff --git a/src/glfw/key_watcher.cc b/src/glfw/key_watcher.cc new file mode 100644 index 0000000..21a570a --- /dev/null +++ b/src/glfw/key_watcher.cc @@ -0,0 +1,24 @@ +#include "key_watcher.h" + +KeyWatcher::KeyWatcher(GLFWwindow* handle, int key): +	_handle(handle), +	_key(key), +	_last_state(glfwGetKey(_handle, _key)) +{ } + +bool KeyWatcher::wasClicked() { +	switch ( glfwGetKey(_handle, _key) ) { +		case GLFW_RELEASE: +			_last_state = GLFW_RELEASE; +			return false; +		case GLFW_PRESS: +			if ( _last_state == GLFW_RELEASE ) { +				_last_state = GLFW_PRESS; +				return true; +			} else { +				return false; +			} +		default: +			return false; +	} +} diff --git a/src/glfw/key_watcher.h b/src/glfw/key_watcher.h new file mode 100644 index 0000000..538829f --- /dev/null +++ b/src/glfw/key_watcher.h @@ -0,0 +1,17 @@ +#pragma once + +#include <GLFW/glfw3.h> + +class KeyWatcher { +private: +	GLFWwindow* const _handle; + +	int _key; +	int _last_state; + +public: +	KeyWatcher(GLFWwindow* handle, int key); + +	bool wasClicked(); + +}; diff --git a/src/glfw/window.cc b/src/glfw/window.cc new file mode 100644 index 0000000..0e57a65 --- /dev/null +++ b/src/glfw/window.cc @@ -0,0 +1,32 @@ +#include "window.h" + +Window::Window(const std::string& title): +	_handle(glfwCreateWindow(_width, _height, title.c_str(), NULL, NULL)) { +	if ( _handle != nullptr ) { +		glfwMakeContextCurrent(_handle); +		if ( glewInit() == GLEW_OK ) { +			_good = true; +		} +		glfwMakeContextCurrent(nullptr); +	} +} + +Window::~Window() { +	glfwDestroyWindow(_handle); +} + +bool Window::isGood() const { +	return _good; +} + +int Window::getWidth() const { +	return _width; +} + +int Window::getHeight() const { +	return _height; +} + +KeyWatcher Window::getKeyWatcher(int key) { +	return KeyWatcher(_handle, key); +} diff --git a/src/glfw/window.h b/src/glfw/window.h new file mode 100644 index 0000000..92a1b56 --- /dev/null +++ b/src/glfw/window.h @@ -0,0 +1,58 @@ +#pragma once + +#include <string> + +#include <GL/glew.h> +#include <GLFW/glfw3.h> + +#include "key_watcher.h" + +class Window { +private: +	bool _good   = false; +	int  _width  = 800; +	int  _height = 600; + +	GLFWwindow* const _handle; + +public: +	Window(const std::string& title); +	~Window(); + +	bool isGood() const; + +	int getWidth() const; +	int getHeight() const; + +	KeyWatcher getKeyWatcher(int key); + +	template <class F> +	void init(F f); + +	template <class F> +	void render(F loop); +}; + +template <class F> +void Window::init(F f) { +	glfwMakeContextCurrent(_handle); +	f(); +	glfwMakeContextCurrent(nullptr); +} + +template <class F> +void Window::render(F loop) { +	glfwMakeContextCurrent(_handle); + +	while ( glfwGetKey(_handle, GLFW_KEY_ESCAPE) != GLFW_PRESS && +	        glfwWindowShouldClose(_handle)       == 0 ) { +		glfwGetWindowSize(_handle, &_width, &_height); + +		loop(); + +		glfwSwapBuffers(_handle); +		glfwPollEvents(); +	} + +	glfwMakeContextCurrent(nullptr); +} diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..914d505 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,156 @@ +#include <memory> +#include <algorithm> +#include <iostream> + +#include <glm/glm.hpp> +#include <glm/gtc/matrix_transform.hpp> + +#include "glfw/guard.h" +#include "glfw/window.h" + +#include "buffer/vertex/fluid_cell_buffer.h" +#include "buffer/vertex/lattice_cell_buffer.h" + +#include "shader/wrap/graphic_shader.h" +#include "shader/wrap/compute_shader.h" + +#include "shader/code/vertex.glsl" +#include "shader/code/fragment.glsl" + +#include "shader/code/collide.glsl" +#include "shader/code/stream.glsl" + +#include "timer.h" + +float getWorldHeight(int window_width, int window_height, float world_width) { +	return world_width / window_width * window_height; +} + +glm::mat4 getMVP(float world_width, float world_height) { +	const glm::mat4 projection = glm::ortho( +		-(world_width/2),  world_width/2, +		-(world_height/2), world_height/2, +		0.1f, 100.0f +	); + +	const glm::mat4 view = glm::lookAt( +		glm::vec3(0,0,1), +		glm::vec3(0,0,0), +		glm::vec3(0,1,0) +	); + +	return projection * view; +} + +int renderWindow() { +	Window window("compustream"); + +	if ( !window.isGood() ) { +		std::cerr << "Failed to open GLFW window." << std::endl; +		return -1; +	} + +	int window_width  = window.getWidth(); +	int window_height = window.getHeight(); + +	float world_width  = 256.0; +	float world_height = getWorldHeight(window_width, window_height, world_width); + +	glm::mat4 MVP = getMVP(world_width,  world_height); + +	std::unique_ptr<GraphicShader> scene_shader; + +	std::unique_ptr<LatticeCellBuffer> lattice_buffer_a; +	std::unique_ptr<LatticeCellBuffer> lattice_buffer_b; +	std::unique_ptr<FluidCellBuffer>   fluid_buffer; + +	std::unique_ptr<ComputeShader> collide_shader; +	std::unique_ptr<ComputeShader> stream_shader; + +	window.init([&]() { +		scene_shader = std::make_unique<GraphicShader>( +			VERTEX_SHADER_CODE, FRAGMENT_SHADER_CODE); + +		lattice_buffer_a = std::make_unique<LatticeCellBuffer>(); +		lattice_buffer_b = std::make_unique<LatticeCellBuffer>(); +		fluid_buffer = std::make_unique<FluidCellBuffer>(); + +		collide_shader = std::make_unique<ComputeShader>(COLLIDE_SHADER_CODE); +		stream_shader = std::make_unique<ComputeShader>(STREAM_SHADER_CODE); +	}); + +	if ( !collide_shader->isGood() || !stream_shader->isGood() ) { +		std::cerr << "Compute shader error. Check vector field definition." << std::endl; +		return -1; +	} + +	auto last_frame = timer::now(); + +	bool update_lattice = true; +	bool tick           = true; + +	auto pause_key = window.getKeyWatcher(GLFW_KEY_SPACE); + +	window.render([&]() { +		if ( pause_key.wasClicked() ) { +			update_lattice = !update_lattice; +		} + +		if (    window.getWidth()  != window_width +		     || window.getHeight() != window_height ) { +			window_width  = window.getWidth(); +			window_height = window.getHeight(); +			glViewport(0, 0, window_width, window_height); + +			world_height  = getWorldHeight(window_width, window_height, world_width); +			MVP = getMVP(world_width, world_height); +		} + +		if ( update_lattice ) { +			if ( timer::millisecondsSince(last_frame) >= 1000/25 ) { +				if ( tick ) { +					collide_shader->workOn(lattice_buffer_a->getBuffer(), lattice_buffer_b->getBuffer(), fluid_buffer->getBuffer()); +					stream_shader->workOn(lattice_buffer_a->getBuffer(), lattice_buffer_b->getBuffer(), fluid_buffer->getBuffer()); +					tick = false; +				} else { +					collide_shader->workOn(lattice_buffer_b->getBuffer(), lattice_buffer_a->getBuffer(), fluid_buffer->getBuffer()); +					stream_shader->workOn(lattice_buffer_b->getBuffer(), lattice_buffer_a->getBuffer(), fluid_buffer->getBuffer()); +					tick = true; +				} + +				{ +					auto guard = collide_shader->use(); +					collide_shader->dispatch(); +				} +				{ +					auto guard = stream_shader->use(); +					stream_shader->dispatch(); +				} + +				last_frame = timer::now(); +			} + +			{ +				auto sdrGuard = scene_shader->use(); + +				scene_shader->setUniform("MVP", MVP); + +				glClear(GL_COLOR_BUFFER_BIT); +				fluid_buffer->draw(); +			} +		} +	}); + +	return 0; +} + +int main(int argc, char* argv[]) { +	GlfwGuard glfw; + +	if( !glfw.isGood() ) { +		std::cerr << "Failed to initialize GLFW." << std::endl; +		return -1; +	} + +	return renderWindow(); +} diff --git a/src/shader/code/collide.glsl b/src/shader/code/collide.glsl new file mode 100644 index 0000000..67e762b --- /dev/null +++ b/src/shader/code/collide.glsl @@ -0,0 +1,95 @@ +static const std::string COLLIDE_SHADER_CODE = R"( +#version 430 + +layout (local_size_x = 1, local_size_y = 1) in; +layout (std430, binding=1) buffer bufferCollide{ float collideCells[]; }; +layout (std430, binding=2) buffer bufferStream{  float streamCells[]; }; +layout (std430, binding=3) buffer bufferFluid{   float fluidCells[]; }; + +float get(uint x, uint y, int i, int j) { +	return collideCells[9*128*y + 9*x + (i+1)*3 + j+1]; +} + +void set(uint x, uint y, int i, int j, float v) { +	collideCells[9*128*y + 9*x + (i+1)*3 + j+1] = v; +} + +void setFluid(uint x, uint y, vec2 v, float d) { +	fluidCells[3*128*y + 3*x + 0] = float(x)-64. + 10.*v.x; +	fluidCells[3*128*y + 3*x + 1] = float(y)-64. + 10.*v.y; +	fluidCells[3*128*y + 3*x + 2] = d; +} + +float density(uint x, uint y) { +	return collideCells[9*128*y + 9*x + 0] +	     + collideCells[9*128*y + 9*x + 1] +	     + collideCells[9*128*y + 9*x + 2] +	     + collideCells[9*128*y + 9*x + 3] +	     + collideCells[9*128*y + 9*x + 4] +	     + collideCells[9*128*y + 9*x + 5] +	     + collideCells[9*128*y + 9*x + 6] +	     + collideCells[9*128*y + 9*x + 7] +	     + collideCells[9*128*y + 9*x + 8]; +} + +vec2 velocity(uint x, uint y, float d) { +	return 1./d * vec2( +		get(x,y, 1, 0) - get(x,y,-1, 0) + get(x,y, 1, 1) - get(x,y,-1,-1) + get(x,y, 1,-1) - get(x,y,-1,1), +		get(x,y, 0, 1) - get(x,y, 0,-1) + get(x,y, 1, 1) - get(x,y,-1,-1) - get(x,y, 1,-1) + get(x,y,-1,1) +	); +} + +float w(int i, int j) { +	if ( i == -1 ) { +		if ( j != 0 ) { +			return 1./36.; +		} else { +			return 1./9.; +		} +	} else if ( i == 0 ) { +		if ( j != 0 ) { +			return 1./9.; +		} else { +			return 4./9.; +		} +	} else { +		if ( j != 0 ) { +			return 1./36.; +		} else { +			return 1./9.; +		} +	} +} + +float comp(int x, int y, vec2 v) { +	return x*v.x + y*v.y; +} + +float sq(float x) { +	return x*x; +} + +float norm(vec2 v) { +	return sqrt(sq(v.x)+sq(v.y)); +} + +void main() { +	const uint x = gl_GlobalInvocationID.x; +	const uint y = gl_GlobalInvocationID.y; + +	const float omega = 0.6; + +	const float d = density(x,y); +	const vec2  v = velocity(x,y,d); + +	setFluid(x,y,v,d); + +	for ( int i = -1; i <= 1; ++i ) { +		for ( int j = -1; j <= 1; ++j ) { +			const float eq = w(i,j) * d * (1 + 3*comp(i,j,v) + 4.5*sq(comp(i,j,v)) - 1.5*sq(norm(v))); +			set(x,y,i,j, get(x,y,i,j) + omega * (eq - get(x,y,i,j))); +		} +	} + +} +)"; diff --git a/src/shader/code/fragment.glsl b/src/shader/code/fragment.glsl new file mode 100644 index 0000000..37e18bd --- /dev/null +++ b/src/shader/code/fragment.glsl @@ -0,0 +1,5 @@ +static const std::string FRAGMENT_SHADER_CODE = R"( +void main() { +	gl_FragColor = gl_Color; +} +)"; diff --git a/src/shader/code/stream.glsl b/src/shader/code/stream.glsl new file mode 100644 index 0000000..7dd5ba8 --- /dev/null +++ b/src/shader/code/stream.glsl @@ -0,0 +1,30 @@ +static const std::string STREAM_SHADER_CODE = R"( +#version 430 + +layout (local_size_x = 1, local_size_y = 1) in; +layout (std430, binding=1) buffer bufferCollide{ float collideCells[]; }; +layout (std430, binding=2) buffer bufferStream{  float streamCells[]; }; + +float get(uint x, uint y, int i, int j) { +	return collideCells[9*128*y + 9*x + (i+1)*3 + j+1]; +} + +void set(uint x, uint y, int i, int j, float v) { +	streamCells[9*128*y + 9*x + (i+1)*3 + j+1] = v; +} + +void main() { +	const uint x = gl_GlobalInvocationID.x; +	const uint y = gl_GlobalInvocationID.y; + +	if ( x != 0 && x != 128-1 && y != 0 && y != 128-1 ) { +		for ( int i = -1; i <= 1; ++i ) { +			for ( int j = -1; j <= 1; ++j ) { +				set(x+i,y+j,i,j, get(x,y,i,j)); +			} +		} +	} else { + +	} +} +)"; diff --git a/src/shader/code/vertex.glsl b/src/shader/code/vertex.glsl new file mode 100644 index 0000000..4c307d8 --- /dev/null +++ b/src/shader/code/vertex.glsl @@ -0,0 +1,8 @@ +static const std::string VERTEX_SHADER_CODE = R"( +uniform mat4 MVP; + +void main() { +	gl_Position = MVP * vec4(gl_Vertex.xy, 0.0, 1.0); +	gl_FrontColor = vec4(1., 0., 0., 0.); +} +)"; diff --git a/src/shader/util.cc b/src/shader/util.cc new file mode 100644 index 0000000..be59ac1 --- /dev/null +++ b/src/shader/util.cc @@ -0,0 +1,56 @@ +#include "util.h" + +#include <iostream> +#include <vector> + +namespace util { + +GLint getUniform(GLuint program, const std::string& name) { +	const GLint uniform = glGetUniformLocation(program, name.c_str()); + +	if ( uniform == -1 ) { +		std::cerr << "Could not bind uniform " << name << std::endl; +		return -1; +	} + +	return uniform; +} + +GLint compileShader(const std::string& source, GLenum type) { +	GLint shader = glCreateShader(type); + +	if ( !shader ) { +		std::cerr << "Cannot create a shader of type " << type << std::endl; +		return -1; +	} + +	const char* source_data = source.c_str(); +	const int source_length = source.size(); + +	glShaderSource(shader, 1, &source_data, &source_length); +	glCompileShader(shader); + +	GLint compiled; +	glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + +	if ( !compiled ) { +		std::cerr << "Cannot compile shader" << std::endl; + +		GLint maxLength = 0; +		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); + +		std::vector<GLchar> errorLog(maxLength); +		glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]); + +		for( auto c : errorLog ) { +			std::cerr << c; +		} +		std::cerr << std::endl; + +		return -1; +	} + +	return shader; +} + +} diff --git a/src/shader/util.h b/src/shader/util.h new file mode 100644 index 0000000..31224e9 --- /dev/null +++ b/src/shader/util.h @@ -0,0 +1,13 @@ +#pragma once + +#include <string> + +#include <GL/glew.h> + +namespace util { + +GLint getUniform(GLuint program, const std::string& name); + +GLint compileShader(const std::string& source, GLenum type); + +} diff --git a/src/shader/wrap/compute_shader.cc b/src/shader/wrap/compute_shader.cc new file mode 100644 index 0000000..c90c370 --- /dev/null +++ b/src/shader/wrap/compute_shader.cc @@ -0,0 +1,51 @@ +#include "compute_shader.h" + +#include "shader/util.h" + +ComputeShader::Guard::Guard(GLuint id): +	_id(id) { +	glUseProgram(_id); +} + +ComputeShader::Guard::~Guard() { +	glUseProgram(0); +} + +ComputeShader::Guard ComputeShader::use() const { +	return Guard(_id); +} + +ComputeShader::ComputeShader(const std::string& src): +	_id(glCreateProgram()) { +	GLint shader = util::compileShader(src, GL_COMPUTE_SHADER); + +	if ( shader != -1 ) { +		glAttachShader(_id, shader); +		glLinkProgram(_id); +		_good = true; +	} +} + +ComputeShader::~ComputeShader() { +	glDeleteProgram(_id); +} + +bool ComputeShader::isGood() const { +	return _good; +} + +GLuint ComputeShader::setUniform(const std::string& name, float x, float y) const { +	GLuint id = util::getUniform(_id, name); +	glUniform2f(id, x, y); +	return id; +} + +void ComputeShader::workOn(GLuint bufferA, GLuint bufferB, GLuint bufferC) const { +	glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, bufferA); +	glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, bufferB); +	glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, bufferC); +} + +void ComputeShader::dispatch() const { +	glDispatchCompute(128, 128, 1); +} diff --git a/src/shader/wrap/compute_shader.h b/src/shader/wrap/compute_shader.h new file mode 100644 index 0000000..74c8270 --- /dev/null +++ b/src/shader/wrap/compute_shader.h @@ -0,0 +1,32 @@ +#pragma once + +#include <string> + +#include <GL/glew.h> + +class ComputeShader { +private: +	const GLuint _id; + +	bool _good; + +public: +	struct Guard { +		const GLuint _id; + +		Guard(GLuint id); +		~Guard(); +	}; + +	Guard use() const; + +	ComputeShader(const std::string& src); +	~ComputeShader(); + +	bool isGood() const; + +	GLuint setUniform(const std::string& name, float x, float y) const; + +	void workOn(GLuint bufferA, GLuint bufferB, GLuint bufferC) const; +	void dispatch() const; +}; diff --git a/src/shader/wrap/graphic_shader.cc b/src/shader/wrap/graphic_shader.cc new file mode 100644 index 0000000..0ed37ff --- /dev/null +++ b/src/shader/wrap/graphic_shader.cc @@ -0,0 +1,45 @@ +#include "graphic_shader.h" + +#include "shader/util.h" + +GraphicShader::Guard::Guard(GLuint id): +	_id(id) { +	glUseProgram(_id); +} + +GraphicShader::Guard::~Guard() { +	glUseProgram(0); +} + +GraphicShader::Guard GraphicShader::use() const { +	return Guard(_id); +} + +GraphicShader::GraphicShader(const std::string& vertex, const std::string fragment): +	_id(glCreateProgram()) { +	glAttachShader(_id, util::compileShader(vertex, GL_VERTEX_SHADER)); +	glAttachShader(_id, util::compileShader(fragment, GL_FRAGMENT_SHADER)); +	glLinkProgram(_id); +} + +GraphicShader::~GraphicShader() { +	glDeleteProgram(_id); +} + +GLuint GraphicShader::setUniform(const std::string& name, int value) const { +	GLuint id = util::getUniform(_id, name); +	glUniform1i(id, value); +	return id; +} + +GLuint GraphicShader::setUniform(const std::string& name, const std::vector<GLuint>& v) const { +	GLuint id = util::getUniform(_id, name); +	glUniform1iv(id, v.size(), reinterpret_cast<const GLint*>(v.data())); +	return id; +} + +GLuint GraphicShader::setUniform(const std::string& name, glm::mat4& M) const { +	GLuint id = util::getUniform(_id, name); +	glUniformMatrix4fv(id, 1, GL_FALSE, &M[0][0]); +	return id; +} diff --git a/src/shader/wrap/graphic_shader.h b/src/shader/wrap/graphic_shader.h new file mode 100644 index 0000000..25a5efb --- /dev/null +++ b/src/shader/wrap/graphic_shader.h @@ -0,0 +1,29 @@ +#pragma once + +#include <vector> +#include <string> + +#include <GL/glew.h> +#include <glm/glm.hpp> + +class GraphicShader { +private: +	const GLuint _id; + +public: +	struct Guard { +		const GLuint _id; + +		Guard(GLuint id); +		~Guard(); +	}; + +	Guard use() const; + +	GraphicShader(const std::string& vertex, const std::string fragment); +	~GraphicShader(); + +	GLuint setUniform(const std::string& name, int value) const; +	GLuint setUniform(const std::string& name, const std::vector<GLuint>& v) const; +	GLuint setUniform(const std::string& name, glm::mat4& M) const; +}; diff --git a/src/timer.cc b/src/timer.cc new file mode 100644 index 0000000..c46017c --- /dev/null +++ b/src/timer.cc @@ -0,0 +1,16 @@ +#include "timer.h" + +namespace timer { + +std::chrono::time_point<std::chrono::high_resolution_clock> now() { +	return std::chrono::high_resolution_clock::now(); +} + +double millisecondsSince( +	std::chrono::time_point<std::chrono::high_resolution_clock>& pit) { +	return std::chrono::duration_cast<std::chrono::milliseconds>( +		now() - pit +	).count(); +} + +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..aed1b61 --- /dev/null +++ b/src/timer.h @@ -0,0 +1,12 @@ +#pragma once + +#include <chrono> + +namespace timer { + +std::chrono::time_point<std::chrono::high_resolution_clock> now(); + +double millisecondsSince( +	std::chrono::time_point<std::chrono::high_resolution_clock>& pit); + +} | 
