Parcourir la source

finish up shader/sampler/texture/buffer loading/unloading/association

jp9000 il y a 12 ans
Parent
commit
83ddb920a1

+ 5 - 4
libobs-d3d11/d3d11-subsystem.cpp

@@ -766,7 +766,8 @@ void device_load_vertexshader(device_t device, shader_t vertshader)
 	if (vertshader) {
 		if (vertshader->type != SHADER_VERTEX) {
 			blog(LOG_ERROR, "device_load_vertexshader (D3D11): "
-			                "Shader is not a vertex shader");
+			                "Specified shader is not a vertex "
+			                "shader");
 			return;
 		}
 
@@ -809,7 +810,8 @@ void device_load_pixelshader(device_t device, shader_t pixelshader)
 	if (pixelshader) {
 		if (pixelshader->type != SHADER_PIXEL) {
 			blog(LOG_ERROR, "device_load_pixelshader (D3D11): "
-			                "Shader is not a pixel shader");
+			                "Specified shader is not a pixel "
+			                "shader");
 			return;
 		}
 
@@ -828,8 +830,7 @@ void device_load_pixelshader(device_t device, shader_t pixelshader)
 	device->context->PSSetSamplers(0, GS_MAX_TEXTURES, states);
 }
 
-void device_load_defaultsamplerstate(device_t device, bool b_3d,
-		int unit)
+void device_load_defaultsamplerstate(device_t device, bool b_3d, int unit)
 {
 	/* TODO */
 }

+ 18 - 0
libobs-opengl/gl-helpers.h

@@ -78,6 +78,24 @@ static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
 	return gl_success("glBindRendebuffer");
 }
 
+static inline bool gl_tex_param_f(GLenum target, GLenum param, GLfloat val)
+{
+	glTexParameterf(target, param, val);
+	return gl_success("glTexParameterf");
+}
+
+static inline bool gl_tex_param_i(GLenum target, GLenum param, GLint val)
+{
+	glTexParameteri(target, param, val);
+	return gl_success("glTexParameteri");
+}
+
+static inline bool gl_active_texture(GLenum texture)
+{
+	glActiveTexture(texture);
+	return gl_success("glActiveTexture");
+}
+
 extern bool gl_init_face(GLenum target, GLenum type, uint32_t num_levels,
 		GLenum format, GLint internal_format, bool compressed,
 		uint32_t width, uint32_t height, uint32_t size, void ***p_data);

+ 11 - 0
libobs-opengl/gl-indexbuffer.c

@@ -100,3 +100,14 @@ enum gs_index_type indexbuffer_gettype(indexbuffer_t ib)
 {
 	return ib->type;
 }
+
+void device_load_indexbuffer(device_t device, indexbuffer_t ib)
+{
+	if (ib == device->cur_index_buffer)
+		return;
+
+	device->cur_index_buffer = ib;
+
+	if (!gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer))
+		blog(LOG_ERROR, "device_load_indexbuffer (GL) failed");
+}

+ 7 - 3
libobs-opengl/gl-shader.c

@@ -93,14 +93,15 @@ static inline bool gl_add_params(struct gs_shader *shader,
 	return true;
 }
 
-static void gl_add_sampler(struct gs_shader *shader,
+static inline void gl_add_sampler(struct gs_shader *shader,
 		struct shader_sampler *sampler)
 {
-	struct gs_sampler_state new_sampler = {0};
+	samplerstate_t new_sampler;
 	struct gs_sampler_info info;
 
 	shader_sampler_convert(sampler, &info);
-	convert_sampler_info(&new_sampler, &info);
+	new_sampler = device_create_samplerstate(shader->device, &info);
+
 	da_push_back(shader->samplers, &new_sampler);
 }
 
@@ -259,6 +260,9 @@ void shader_destroy(shader_t shader)
 	if (!shader)
 		return;
 
+	for (i = 0; i < shader->samplers.num; i++)
+		samplerstate_destroy(shader->samplers.array[i]);
+
 	for (i = 0; i < shader->params.num; i++)
 		shader_param_free(shader->params.array+i);
 

+ 199 - 11
libobs-opengl/gl-subsystem.c

@@ -34,18 +34,30 @@ device_t device_create(struct gs_init_data *info)
 	memset(device, 0, sizeof(struct gs_device));
 
 	device->plat = gl_platform_create(device, info);
-	if (!device->plat) {
-		blog(LOG_ERROR, "device_create (GL) failed");
-		bfree(device);
-		return NULL;
-	}
+	if (!device->plat)
+		goto fail;
+
+	glGenProgramPipelines(1, &device->pipeline);
+	if (!gl_success("glGenProgramPipelines"))
+		goto fail;
+
+	glBindProgramPipeline(device->pipeline);
+	if (!gl_success("glBindProgramPipeline"))
+		goto fail;
 
 	return device;
+
+fail:
+	blog(LOG_ERROR, "device_create (GL) failed");
+	bfree(device);
+	return NULL;
 }
 
 void device_destroy(device_t device)
 {
 	if (device) {
+		if (device->pipeline)
+			glDeleteProgramPipelines(1, &device->pipeline);
 		gl_platform_destroy(device->plat);
 		bfree(device);
 	}
@@ -107,6 +119,8 @@ samplerstate_t device_create_samplerstate(device_t device,
 
 	sampler = bmalloc(sizeof(struct gs_sampler_state));
 	memset(sampler, 0, sizeof(struct gs_sampler_state));
+	sampler->device = device;
+	sampler->ref    = 1;
 
 	convert_sampler_info(sampler, info);
 	return sampler;
@@ -118,46 +132,220 @@ enum gs_texture_type device_gettexturetype(device_t device,
 	return texture->type;
 }
 
-void device_load_indexbuffer(device_t device, indexbuffer_t indexbuffer)
+static bool load_texture_sampler(texture_t tex, samplerstate_t ss)
 {
+	bool success = true;
+	if (tex->cur_sampler == ss)
+		return true;
+
+	if (tex->cur_sampler)
+		samplerstate_release(tex->cur_sampler);
+	tex->cur_sampler = ss;
+	if (!ss)
+		return true;
+
+	samplerstate_addref(ss);
+
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_MIN_FILTER,
+				ss->min_filter))
+		success = false;
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_MAG_FILTER,
+				ss->mag_filter))
+		success = false;
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_WRAP_S, ss->address_u))
+		success = false;
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_WRAP_T, ss->address_v))
+		success = false;
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_WRAP_R, ss->address_w))
+		success = false;
+	if (!gl_tex_param_i(tex->gl_target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
+			ss->max_anisotropy))
+		success = false;
+
+	return success;
+}
+
+static inline struct shader_param *get_texture_param(device_t device, int unit)
+{
+	struct gs_shader *shader = device->cur_pixel_shader;
+	size_t i;
+
+	for (i = 0; i < shader->params.num; i++) {
+		struct shader_param *param = shader->params.array+i;
+		if (param->type == SHADER_PARAM_TEXTURE) {
+			if (param->texture_id == unit)
+				return param;
+		}
+	}
+
+	return NULL;
 }
 
 void device_load_texture(device_t device, texture_t tex, int unit)
 {
+	struct shader_param *param;
+	struct gs_sampler_state *sampler;
+
+	/* need a pixel shader to properly bind textures */
+	if (!device->cur_pixel_shader)
+		tex = NULL;
+
+	if (device->cur_textures[unit] == tex)
+		return;
+
+	device->cur_textures[unit] = tex;
+	param = get_texture_param(device, unit);
+	if (!param)
+		return;
+
+	param->texture = tex;
+
+	if (!tex)
+		return;
+
+	sampler = device->cur_samplers[param->sampler_id];
+
+	if (!gl_active_texture(GL_TEXTURE0 + unit))
+		goto fail;
+	if (!gl_bind_texture(tex->gl_target, tex->texture))
+		goto fail;
+	if (sampler && !load_texture_sampler(tex, sampler))
+		goto fail;
+
+	return;
+
+fail:
+	blog(LOG_ERROR, "device_load_texture (GL) failed");
+}
+
+static bool load_sampler_on_textures(device_t device, samplerstate_t ss,
+		int sampler_unit)
+{
+	struct gs_shader *shader = device->cur_pixel_shader;
+	size_t i;
+
+	for (i = 0; i < shader->params.num; i++) {
+		struct shader_param *param = shader->params.array+i;
+
+		if (param->type == SHADER_PARAM_TEXTURE &&
+		    param->sampler_id == sampler_unit &&
+		    param->texture) {
+			if (!gl_active_texture(GL_TEXTURE0 + param->texture_id))
+				return false;
+			if (!load_texture_sampler(param->texture, ss))
+				return false;
+		}
+	}
+
+	return true;
 }
 
-void device_load_samplerstate(device_t device,
-		samplerstate_t samplerstate, int unit)
+void device_load_samplerstate(device_t device, samplerstate_t ss, int unit)
 {
+	/* need a pixel shader to properly bind samplers */
+	if (!device->cur_pixel_shader)
+		ss = NULL;
+
+	if (device->cur_samplers[unit] == ss)
+		return;
+
+	device->cur_samplers[unit] = ss;
+
+	if (!ss)
+		return;
+
+	if (!load_sampler_on_textures(device, ss, unit))
+		blog(LOG_ERROR, "device_load_samplerstate (GL) failed");
+
+	return;
 }
 
 void device_load_vertexshader(device_t device, shader_t vertshader)
 {
+	GLuint program = 0;
+	vertbuffer_t cur_vb = device->cur_vertex_buffer;
+
+	if (device->cur_vertex_shader == vertshader)
+		return;
+
+	if (vertshader->type != SHADER_VERTEX) {
+		blog(LOG_ERROR, "Specified shader is not a vertex shader");
+		goto fail;
+	}
+
+	/* unload and reload the vertex buffer to sync the buffers up with
+	 * the specific shader */
+	if (cur_vb && !vertexbuffer_load(device, NULL))
+		goto fail;
+
+	device->cur_vertex_shader = vertshader;
+
+	if (vertshader)
+		program = vertshader->program;
+
+	glUseProgramStages(device->pipeline, GL_VERTEX_SHADER, program);
+	if (!gl_success("glUseProgramStages"))
+		goto fail;
+
+	if (cur_vb && !vertexbuffer_load(device, cur_vb))
+		goto fail;
+
+	return;
+
+fail:
+	blog(LOG_ERROR, "device_load_vertexshader (GL) failed");
 }
 
 void device_load_pixelshader(device_t device, shader_t pixelshader)
 {
+	GLuint program = 0;
+	if (device->cur_pixel_shader == pixelshader)
+		return;
+
+	if (pixelshader->type != SHADER_PIXEL) {
+		blog(LOG_ERROR, "Specified shader is not a pixel shader");
+		goto fail;
+	}
+
+	device->cur_pixel_shader = pixelshader;
+
+	if (pixelshader)
+		program = pixelshader->program;
+
+	glUseProgramStages(device->pipeline, GL_FRAGMENT_SHADER,
+			pixelshader->program);
+	if (!gl_success("glUseProgramStages"))
+		goto fail;
+
+	return;
+
+fail:
+	blog(LOG_ERROR, "device_load_pixelshader (GL) failed");
 }
 
-void device_load_defaultsamplerstate(device_t device, bool b_3d,
-		int unit)
+void device_load_defaultsamplerstate(device_t device, bool b_3d, int unit)
 {
+	/* TODO */
 }
 
 shader_t device_getvertexshader(device_t device)
 {
+	return device->cur_vertex_shader;
 }
 
 shader_t device_getpixelshader(device_t device)
 {
+	return device->cur_pixel_shader;
 }
 
 texture_t device_getrendertarget(device_t device)
 {
+	return device->cur_render_target;
 }
 
 zstencil_t device_getzstenciltarget(device_t device)
 {
+	return device->cur_zstencil_buffer;
 }
 
 void device_setrendertarget(device_t device, texture_t tex,
@@ -347,5 +535,5 @@ enum gs_color_format volumetexture_getcolorformat(texture_t voltex)
 
 void samplerstate_destroy(samplerstate_t samplerstate)
 {
-	bfree(samplerstate);
+	samplerstate_release(samplerstate);
 }

+ 25 - 3
libobs-opengl/gl-subsystem.h

@@ -185,6 +185,9 @@ extern void convert_sampler_info(struct gs_sampler_state *sampler,
 		struct gs_sampler_info *info);
 
 struct gs_sampler_state {
+	device_t             device;
+	volatile uint32_t    ref;
+
 	GLint                min_filter;
 	GLint                mag_filter;
 	GLint                address_u;
@@ -193,6 +196,17 @@ struct gs_sampler_state {
 	GLint                max_anisotropy;
 };
 
+static inline void samplerstate_addref(samplerstate_t ss)
+{
+	ss->ref++;
+}
+
+static inline void samplerstate_release(samplerstate_t ss)
+{
+	if (--ss->ref == 0)
+		bfree(ss);
+}
+
 struct shader_param {
 	enum shader_param_type type;
 
@@ -232,9 +246,9 @@ struct gs_shader {
 	struct shader_param  *viewproj;
 	struct shader_param  *world;
 
-	DARRAY(struct shader_attrib)    attribs;
-	DARRAY(struct gs_sampler_state) samplers;
-	DARRAY(struct shader_param)     params;
+	DARRAY(struct shader_attrib) attribs;
+	DARRAY(struct shader_param)  params;
+	DARRAY(samplerstate_t)       samplers;
 };
 
 struct gs_vertex_buffer {
@@ -250,6 +264,8 @@ struct gs_vertex_buffer {
 	struct vb_data       *data;
 };
 
+extern bool vertexbuffer_load(device_t device, vertbuffer_t vb);
+
 struct gs_index_buffer {
 	GLuint               buffer;
 	enum gs_index_type   type;
@@ -267,6 +283,7 @@ struct gs_texture {
 	enum gs_texture_type type;
 	enum gs_color_format format;
 	GLenum               gl_format;
+	GLenum               gl_target;
 	GLint                gl_internal_format;
 	GLenum               gl_type;
 	GLuint               texture;
@@ -274,6 +291,8 @@ struct gs_texture {
 	bool                 is_dynamic;
 	bool                 is_render_target;
 	bool                 gen_mipmaps;
+
+	samplerstate_t       cur_sampler;
 };
 
 struct gs_texture_2d {
@@ -318,6 +337,7 @@ struct gs_swap_chain {
 
 struct gs_device {
 	struct gl_platform   *plat;
+	GLuint               pipeline;
 	enum copy_type       copy_type;
 
 	texture_t            cur_render_target;
@@ -330,6 +350,8 @@ struct gs_device {
 	shader_t             cur_vertex_shader;
 	shader_t             cur_pixel_shader;
 	swapchain_t          cur_swap;
+
+	bool                 texture_changed[GS_MAX_TEXTURES];
 };
 
 extern struct gl_platform   *gl_platform_create(device_t device,

+ 1 - 0
libobs-opengl/gl-texture2d.c

@@ -78,6 +78,7 @@ texture_t device_create_texture(device_t device, uint32_t width,
 	tex->base.gl_format          = convert_gs_format(color_format);
 	tex->base.gl_internal_format = convert_gs_internal_format(color_format);
 	tex->base.gl_type            = get_gl_format_type(color_format);
+	tex->base.gl_target          = GL_TEXTURE_2D;
 	tex->base.is_dynamic         = flags & GS_DYNAMIC;
 	tex->base.is_render_target   = flags & GS_RENDERTARGET;
 	tex->base.gen_mipmaps        = flags & GS_BUILDMIPMAPS;

+ 2 - 1
libobs-opengl/gl-texturecube.c

@@ -61,10 +61,11 @@ texture_t device_create_cubetexture(device_t device, uint32_t size,
 	memset(tex, 0, sizeof(struct gs_texture_2d));
 
 	tex->base.device             = device;
-	tex->base.type               = GS_TEXTURE_2D;
+	tex->base.type               = GS_TEXTURE_CUBE;
 	tex->base.format             = color_format;
 	tex->base.gl_format          = convert_gs_format(color_format);
 	tex->base.gl_internal_format = convert_gs_internal_format(color_format);
+	tex->base.gl_target          = GL_TEXTURE_CUBE_MAP;
 	tex->base.is_render_target   = flags & GS_RENDERTARGET;
 	tex->base.gen_mipmaps        = flags & GS_BUILDMIPMAPS;
 	tex->size                    = size;

+ 12 - 4
libobs-opengl/gl-vertexbuffer.c

@@ -241,15 +241,23 @@ static inline bool load_vb_buffers(struct gs_shader *shader,
 	return true;
 }
 
-void device_load_vertexbuffer(device_t device, vertbuffer_t vb)
+bool vertexbuffer_load(device_t device, vertbuffer_t vb)
 {
 	if (device->cur_vertex_buffer == vb)
-		return;
+		return true;
 
 	device->cur_vertex_buffer = vb;
-	if (!device->cur_vertex_shader)
-		return;
+	if (!device->cur_vertex_shader || !vb)
+		return true;
 
 	if (!load_vb_buffers(device->cur_vertex_shader, vb))
+		return false;
+
+	return true;
+}
+
+void device_load_vertexbuffer(device_t device, vertbuffer_t vb)
+{
+	if (vertexbuffer_load(device, vb))
 		blog(LOG_ERROR, "device_load_vertexbuffer (GL) failed");
 }