Browse Source

add stage surfaces and texture copying

jp9000 12 years ago
parent
commit
85e2fc6b07

+ 34 - 6
libobs-opengl/gl-helpers.c

@@ -17,7 +17,7 @@
 
 #include "gl-subsystem.h"
 
-bool upload_face(GLenum type, uint32_t num_levels,
+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)
 {
@@ -27,19 +27,21 @@ bool upload_face(GLenum type, uint32_t num_levels,
 
 	for (i = 0; i < num_levels; i++) {
 		if (compressed) {
-			glCompressedTexImage2D(type, i, internal_format,
-					width, height, 0, size, *data);
+			glCompressedTexImage2D(target, i, internal_format,
+					width, height, 0, size,
+					data ? *data : NULL);
 			if (!gl_success("glCompressedTexImage2D"))
 				success = false;
 
 		} else {
-			glTexImage2D(type, i, internal_format, width, height, 0,
-					format, GL_UNSIGNED_BYTE, *data);
+			glTexImage2D(target, i, internal_format, width, height,
+					0, format, type, data ? *data : NULL);
 			if (!gl_success("glTexImage2D"))
 				success = false;
 		}
 
-		data++;
+		if (data)
+			data++;
 		size   /= 4;
 		width  /= 2;
 		height /= 2;
@@ -51,3 +53,29 @@ bool upload_face(GLenum type, uint32_t num_levels,
 	*p_data = data;
 	return success;
 }
+
+bool gl_copy_texture(struct gs_device *device,
+                     GLuint src, GLenum src_target,
+                     GLuint dst, GLenum dst_target,
+                     uint32_t width, uint32_t height)
+{
+	bool success = false;
+
+	if (device->copy_type == COPY_TYPE_ARB) {
+		glCopyImageSubData(src, src_target, 0, 0, 0, 0,
+		                   dst, dst_target, 0, 0, 0, 0,
+		                   width, height, 1);
+		success = gl_success("glCopyImageSubData");
+
+	} else if (device->copy_type == COPY_TYPE_NV) {
+		glCopyImageSubDataNV(src, src_target, 0, 0, 0, 0,
+		                     dst, dst_target, 0, 0, 0, 0,
+		                     width, height, 1);
+		success = gl_success("glCopyImageSubDataNV");
+
+	} else if (device->copy_type == COPY_TYPE_FBO_BLIT) {
+		/* TODO (implement FBOs) */
+	}
+
+	return success;
+}

+ 6 - 1
libobs-opengl/gl-helpers.h

@@ -66,8 +66,13 @@ static inline bool gl_bind_renderbuffer(GLenum target, GLuint buffer)
 	return gl_success("glBindRendebuffer");
 }
 
-extern bool upload_face(GLenum type, uint32_t num_levels,
+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);
 
+extern bool gl_copy_texture(struct gs_device *device,
+                            GLuint src, GLenum src_target,
+                            GLuint dst, GLenum dst_target,
+                            uint32_t width, uint32_t height);
+
 #endif

+ 174 - 0
libobs-opengl/gl-stagesurf.c

@@ -0,0 +1,174 @@
+/******************************************************************************
+    Copyright (C) 2013 by Hugh Bailey <[email protected]>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+******************************************************************************/
+
+#include "gl-subsystem.h"
+
+static bool create_pixel_pack_buffer(struct gs_stage_surface *surf)
+{
+	GLsizeiptr size;
+	bool success = true;
+
+	if (!gl_gen_buffers(1, &surf->pack_buffer))
+		return false;
+
+	if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, surf->pack_buffer))
+		return false;
+
+	size = surf->width * surf->height * surf->bytes_per_pixel;
+
+	glBufferData(GL_PIXEL_PACK_BUFFER, size, 0, GL_DYNAMIC_READ);
+	if (!gl_success("glBufferData"))
+		success = false;
+
+	if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0))
+		success = false;
+
+	return success;
+}
+
+static bool gl_init_stage_surface(struct gs_stage_surface *surf)
+{
+	GLenum gl_type = get_gl_format_type(surf->format);
+	bool success = true;
+
+	if (!gl_gen_textures(1, &surf->texture))
+		return false;
+	if (!gl_bind_texture(GL_TEXTURE_2D, surf->texture))
+		return false;
+
+	if (!gl_init_face(GL_TEXTURE_2D, gl_type, 1, surf->gl_format,
+			surf->gl_internal_format, false,
+			surf->width, surf->height, 0, NULL))
+		success = false;
+
+	if (!gl_bind_texture(GL_TEXTURE_2D, 0))
+		success = false;
+
+	if (success)
+		success = create_pixel_pack_buffer(surf);
+
+	return success;
+}
+
+stagesurf_t device_create_stagesurface(device_t device, uint32_t width,
+		uint32_t height, enum gs_color_format color_format)
+{
+	struct gs_stage_surface *surf;
+	surf = bmalloc(sizeof(struct gs_stage_surface));
+	memset(surf, 0, sizeof(struct gs_stage_surface));
+
+	surf->format             = color_format;
+	surf->width              = width;
+	surf->height             = height;
+	surf->gl_format          = convert_gs_format(color_format);
+	surf->gl_internal_format = convert_gs_internal_format(color_format);
+	surf->bytes_per_pixel    = gs_get_format_bpp(color_format)/8;
+
+	if (!gl_init_stage_surface(surf)) {
+		blog(LOG_ERROR, "device_create_stagesurface (GL) failed");
+		stagesurface_destroy(surf);
+		return NULL;
+	}
+
+	return surf;
+}
+
+void stagesurface_destroy(stagesurf_t stagesurf)
+{
+	if (stagesurf) {
+		if (stagesurf->pack_buffer) {
+			glDeleteBuffers(1, &stagesurf->pack_buffer);
+			gl_success("glDeleteBuffers");
+		}
+
+		if (stagesurf->texture) {
+			glDeleteTextures(1, &stagesurf->texture);
+			gl_success("glDeleteTextures");
+		}
+
+		bfree(stagesurf);
+	}
+}
+
+void device_stage_texture(device_t device, stagesurf_t dst, texture_t src)
+{
+	struct gs_texture_2d *tex2d = (struct gs_texture_2d*)src;
+	if (src->type != GS_TEXTURE_2D) {
+		blog(LOG_ERROR, "Source texture must be a 2D texture");
+		goto failed;
+	}
+
+	if (tex2d->width != dst->width || tex2d->height != dst->height) {
+		blog(LOG_ERROR, "Source and destination do not match in size");
+		goto failed;
+	}
+
+	if (!gl_copy_texture(device, tex2d->base.texture, GL_TEXTURE_2D,
+				dst->texture, GL_TEXTURE_2D,
+				dst->width, dst->height))
+		goto failed;
+
+	return;
+
+failed:
+	blog(LOG_ERROR, "device_stage_texture (GL) failed");
+}
+
+uint32_t stagesurface_getwidth(stagesurf_t stagesurf)
+{
+	return stagesurf->width;
+}
+
+uint32_t stagesurface_getheight(stagesurf_t stagesurf)
+{
+	return stagesurf->height;
+}
+
+enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf)
+{
+	return stagesurf->format;
+}
+
+bool stagesurface_map(stagesurf_t stagesurf, const void **data,
+		uint32_t *byte_width)
+{
+	if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
+		goto fail;
+
+	*data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
+	if (!gl_success("glMapBuffer"))
+		goto fail;
+
+	gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
+
+	*byte_width = stagesurf->bytes_per_pixel * stagesurf->width;
+	return true;
+
+fail:
+	blog(LOG_ERROR, "stagesurf_map (GL) failed");
+	return false;
+}
+
+void stagesurface_unmap(stagesurf_t stagesurf)
+{
+	if (!gl_bind_buffer(GL_PIXEL_PACK_BUFFER, stagesurf->pack_buffer))
+		return;
+
+	glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
+	gl_success("glUnmapBuffer");
+	gl_bind_buffer(GL_PIXEL_PACK_BUFFER, 0);
+}

+ 0 - 35
libobs-opengl/gl-subsystem.c

@@ -100,11 +100,6 @@ texture_t device_create_volumetexture(device_t device, uint32_t width,
 	return NULL;
 }
 
-stagesurf_t device_create_stagesurface(device_t device, uint32_t width,
-		uint32_t height, enum gs_color_format color_format)
-{
-}
-
 samplerstate_t device_create_samplerstate(device_t device,
 		struct gs_sampler_info *info)
 {
@@ -196,11 +191,6 @@ void device_copy_texture(device_t device, texture_t dst, texture_t src)
 {
 }
 
-void device_stage_texture(device_t device, stagesurf_t dst,
-		texture_t src)
-{
-}
-
 void device_beginscene(device_t device)
 {
 }
@@ -363,31 +353,6 @@ enum gs_color_format volumetexture_getcolorformat(texture_t voltex)
 {
 }
 
-void stagesurface_destroy(stagesurf_t stagesurf)
-{
-}
-
-uint32_t stagesurface_getwidth(stagesurf_t stagesurf)
-{
-}
-
-uint32_t stagesurface_getheight(stagesurf_t stagesurf)
-{
-}
-
-enum gs_color_format stagesurface_getcolorformat(stagesurf_t stagesurf)
-{
-}
-
-bool stagesurface_map(stagesurf_t stagesurf, const void **data,
-		uint32_t *byte_width)
-{
-}
-
-void stagesurface_unmap(stagesurf_t stagesurf)
-{
-}
-
 void samplerstate_destroy(samplerstate_t samplerstate)
 {
 }

+ 43 - 0
libobs-opengl/gl-subsystem.h

@@ -27,6 +27,12 @@
 struct gl_platform;
 struct gl_windowinfo;
 
+enum copy_type {
+	COPY_TYPE_ARB,
+	COPY_TYPE_NV,
+	COPY_TYPE_FBO_BLIT
+};
+
 static inline GLint convert_gs_format(enum gs_color_format format)
 {
 	switch (format) {
@@ -75,6 +81,30 @@ static inline GLint convert_gs_internal_format(enum gs_color_format format)
 	}
 }
 
+static inline GLenum get_gl_format_type(enum color_format format)
+{
+	switch (format) {
+	case GS_A8:          return GL_UNSIGNED_BYTE;
+	case GS_R8:          return GL_UNSIGNED_BYTE;
+	case GS_RGBA:        return GL_UNSIGNED_BYTE;
+	case GS_BGRX:        return GL_UNSIGNED_BYTE;
+	case GS_BGRA:        return GL_UNSIGNED_BYTE;
+	case GS_R10G10B10A2: return GL_UNSIGNED_INT_10_10_10_2;
+	case GS_RGBA16:      return GL_UNSIGNED_SHORT;
+	case GS_R16:         return GL_UNSIGNED_SHORT;
+	case GS_RGBA16F:     return GL_UNSIGNED_SHORT;
+	case GS_RGBA32F:     return GL_FLOAT;
+	case GS_RG16F:       return GL_UNSIGNED_SHORT;
+	case GS_RG32F:       return GL_FLOAT;
+	case GS_R16F:        return GL_UNSIGNED_SHORT;
+	case GS_R32F:        return GL_FLOAT;
+	case GS_DXT1:        return GL_UNSIGNED_BYTE;
+	case GS_DXT3:        return GL_UNSIGNED_BYTE;
+	case GS_DXT5:        return GL_UNSIGNED_BYTE;
+	default:             return 0;
+	}
+}
+
 static inline GLenum convert_zstencil_format(enum gs_zstencil_format format)
 {
 	switch (format) {
@@ -218,6 +248,18 @@ struct gs_texture_cube {
 	uint32_t             size;
 };
 
+struct gs_stage_surface {
+	enum gs_color_format format;
+	uint32_t             width;
+	uint32_t             height;
+
+	uint32_t             bytes_per_pixel;
+	GLenum               gl_format;
+	GLint                gl_internal_format;
+	GLuint               texture;
+	GLuint               pack_buffer;
+};
+
 struct gs_zstencil_buffer {
 	device_t             device;
 	GLuint               buffer;
@@ -232,6 +274,7 @@ struct gs_swap_chain {
 
 struct gs_device {
 	struct gl_platform   *plat;
+	enum copy_type       copy_type;
 
 	struct gs_texture    *cur_render_texture;
 	int                  cur_render_side;

+ 5 - 6
libobs-opengl/gl-texture2d.c

@@ -23,6 +23,7 @@ static bool upload_texture_2d(struct gs_texture_2d *tex, void **data)
 	uint32_t tex_size   = tex->height * row_size / 8;
 	uint32_t num_levels = tex->base.levels;
 	bool     compressed = gs_is_compressed_format(tex->base.format);
+	GLenum   gl_type    = get_gl_format_type(tex->base.format);
 	bool     success;
 
 	if (!num_levels)
@@ -31,7 +32,7 @@ static bool upload_texture_2d(struct gs_texture_2d *tex, void **data)
 	if (!gl_bind_texture(GL_TEXTURE_2D, tex->base.texture))
 		return false;
 
-	success = upload_face(GL_TEXTURE_2D, num_levels,
+	success = gl_init_face(GL_TEXTURE_2D, gl_type, num_levels,
 			tex->base.gl_format, tex->base.gl_internal_format,
 			compressed, tex->width, tex->height, tex_size, &data);
 
@@ -87,7 +88,7 @@ texture_t device_create_texture(device_t device, uint32_t width,
 		goto fail;
 	if (tex->base.is_dynamic && !create_pixel_unpack_buffer(tex))
 		goto fail;
-	if (data && !upload_texture_2d(tex, data))
+	if (!upload_texture_2d(tex, data))
 		goto fail;
 
 	return (texture_t)tex;
@@ -167,10 +168,8 @@ bool texture_map(texture_t tex, void **ptr, uint32_t *byte_width)
 		goto fail;
 
 	*ptr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
-	if (!*ptr) {
-		gl_success("glMapBuffer");
+	if (!gl_success("glMapBuffer"))
 		goto fail;
-	}
 
 	gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
 
@@ -190,8 +189,8 @@ void texture_unmap(texture_t tex)
 
 	if (!gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, tex2d->unpack_buffer))
 		return;
+
 	glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
 	gl_success("glUnmapBuffer");
-
 	gl_bind_buffer(GL_PIXEL_UNPACK_BUFFER, 0);
 }

+ 9 - 6
libobs-opengl/gl-texturecube.c

@@ -23,6 +23,7 @@ static inline bool upload_texture_cube(struct gs_texture_cube *tex, void **data)
 	uint32_t tex_size   = tex->size * row_size / 8;
 	uint32_t num_levels = tex->base.levels;
 	bool     compressed = gs_is_compressed_format(tex->base.format);
+	GLenum   gl_type    = get_gl_format_type(tex->base.format);
 	bool     success    = true;
 	uint32_t i;
 
@@ -30,21 +31,23 @@ static inline bool upload_texture_cube(struct gs_texture_cube *tex, void **data)
 		num_levels = gs_num_total_levels(tex->size, tex->size);
 
 	for (i = 0; i < 6; i++) {
-		GLenum type = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+		GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
 
-		if (!gl_bind_texture(type, tex->base.texture))
+		if (!gl_bind_texture(target, tex->base.texture))
 			success = false;
 
-		if (!upload_face(type, num_levels, tex->base.gl_format,
+		if (!gl_init_face(target, gl_type, num_levels,
+					tex->base.gl_format,
 					tex->base.gl_internal_format,
 					compressed, tex->size, tex->size,
 					tex_size, &data))
 			success = false;
 
-		if (!gl_bind_texture(type, 0))
+		if (!gl_bind_texture(target, 0))
 			success = false;
 
-		data++;
+		if (data)
+			data++;
 	}
 
 	return success;
@@ -68,7 +71,7 @@ texture_t device_create_cubetexture(device_t device, uint32_t size,
 
 	if (!gl_gen_textures(1, &tex->base.texture))
 		goto fail;
-	if (data && !upload_texture_cube(tex, data))
+	if (!upload_texture_cube(tex, data))
 		goto fail;
 
 	return (texture_t)tex;

+ 9 - 3
libobs-opengl/gl-windows.c

@@ -194,7 +194,7 @@ static inline void required_extension_error(const char *extension)
 	blog(LOG_ERROR, "OpenGL extension %s is required", extension);
 }
 
-static bool gl_init_extensions(void)
+static bool gl_init_extensions(device_t device)
 {
 	GLenum errorcode = glewInit();
 	if (errorcode != GLEW_OK) {
@@ -218,6 +218,13 @@ static bool gl_init_extensions(void)
 		return false;
 	}
 
+	if (GL_ARB_copy_image)
+		device->copy_type = COPY_TYPE_ARB;
+	else if (GLEW_NV_copy_image)
+		device->copy_type = COPY_TYPE_NV;
+	else
+		device->copy_type = COPY_TYPE_FBO_BLIT;
+
 	return true;
 }
 
@@ -341,7 +348,7 @@ struct gl_platform *gl_platform_create(device_t device,
 
 	if (!gl_dummy_context_init(&dummy))
 		goto fail;
-	if (!gl_init_extensions())
+	if (!gl_init_extensions(device))
 		goto fail;
 
 	/* you have to have a dummy context open before you can actually
@@ -401,7 +408,6 @@ struct gl_windowinfo *gl_windowinfo_create(struct gs_init_data *info)
 
 	if (!gl_get_pixel_format(wi->hdc, info, &pixel_format, &pfd))
 		goto fail;
-
 	if (!gl_set_pixel_format(wi->hdc, pixel_format, &pfd))
 		goto fail;
 

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

@@ -45,6 +45,7 @@ zstencil_t device_create_zstencil(device_t device, uint32_t width,
 	zs->format = convert_zstencil_format(format);
 
 	if (!gl_init_zsbuffer(zs, width, height)) {
+		blog(LOG_ERROR, "device_create_zstencil (GL) failed");
 		zstencil_destroy(zs);
 		return NULL;
 	}

+ 1 - 0
vs/2010/libobs-opengl/libobs-opengl.vcxproj

@@ -164,6 +164,7 @@
     <ClCompile Include="..\..\..\libobs-opengl\gl-helpers.c" />
     <ClCompile Include="..\..\..\libobs-opengl\gl-shader.c" />
     <ClCompile Include="..\..\..\libobs-opengl\gl-shaderparser.c" />
+    <ClCompile Include="..\..\..\libobs-opengl\gl-stagesurf.c" />
     <ClCompile Include="..\..\..\libobs-opengl\gl-subsystem.c" />
     <ClCompile Include="..\..\..\libobs-opengl\gl-texture2d.c" />
     <ClCompile Include="..\..\..\libobs-opengl\gl-texturecube.c" />

+ 3 - 0
vs/2010/libobs-opengl/libobs-opengl.vcxproj.filters

@@ -53,5 +53,8 @@
     <ClCompile Include="..\..\..\libobs-opengl\gl-zstencil.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\libobs-opengl\gl-stagesurf.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>