[Bf-blender-cvs] [309b4ad] decklink: BGE: multisample FBO supported in bge.render.offscreenCreate()

Benoit Bolsee noreply at git.blender.org
Mon Nov 2 13:19:12 CET 2015


Commit: 309b4ad8407f3c2af3190cf61c36609f690936c6
Author: Benoit Bolsee
Date:   Mon Nov 2 13:15:50 2015 +0100
Branches: decklink
https://developer.blender.org/rB309b4ad8407f3c2af3190cf61c36609f690936c6

BGE: multisample FBO supported in bge.render.offscreenCreate()

3rd optional argument to offScreenCreate() to specify the number of
multi-sample. If the GPU does not support MSAA on FBO, this is ignored.
No other change in the API.

===================================================================

M	source/blender/gpu/GPU_extensions.h
M	source/blender/gpu/intern/gpu_extensions.c
M	source/gameengine/Ketsji/KX_PythonInit.cpp
M	source/gameengine/Rasterizer/RAS_IOffScreen.h
M	source/gameengine/Rasterizer/RAS_IRasterizer.h
M	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
M	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
M	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
M	source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
M	source/gameengine/VideoTexture/ImageRender.cpp

===================================================================

diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index 685ae59..1ae6474 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -189,6 +189,7 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
 int GPU_offscreen_width(const GPUOffScreen *ofs);
 int GPU_offscreen_height(const GPUOffScreen *ofs);
 int GPU_offscreen_color_texture(const GPUOffScreen *ofs);
+int GPU_offscreen_color_target(const GPUOffScreen *ofs);
 
 /* Builtin/Non-generated shaders */
 typedef enum GPUProgramType {
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index e1dff03..8567dd2 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -1621,6 +1621,11 @@ int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
 	return ofs->color->bindcode;
 }
 
+int GPU_offscreen_color_target(const GPUOffScreen *ofs)
+{
+	return ofs->color->target;
+}
+
 /* GPUShader */
 
 struct GPUShader {
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index b01073e..6effb71 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -1501,10 +1501,11 @@ static PyGetSetDef RASOffScreen_getseters[] = {
 
 static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObject *kwargs)
 {
-	int width, height;
-	const char *keywords[] = {"width", "height",  NULL};
+	int width, height, samples;
+	const char *keywords[] = {"width", "height", "samples", NULL};
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:RASOffscreen", (char **)keywords, &width, &height)) {
+	samples = 0;
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:RASOffscreen", (char **)keywords, &width, &height, &samples)) {
 		return -1;
 	}
 
@@ -1518,12 +1519,17 @@ static int PyRASOffScreen__tp_init(PyRASOffScreen *self, PyObject *args, PyObjec
 		return -1;
 	}
 
+	if (samples < 0) {
+		PyErr_SetString(PyExc_ValueError, "negative 'samples' given");
+		return -1;
+	}
+
 	if (!gp_Rasterizer)
 	{
 		PyErr_SetString(PyExc_SystemError, "no rasterizer");
 		return -1;
 	}
-	self->ofs = gp_Rasterizer->CreateOffScreen(width, height);
+	self->ofs = gp_Rasterizer->CreateOffScreen(width, height, samples);
 	if (!self->ofs) {
 		PyErr_SetString(PyExc_SystemError, "creation failed");
 		return -1;
@@ -1586,8 +1592,10 @@ static PyObject *gPyOffScreenCreate(PyObject *UNUSED(self), PyObject *args)
 {
 	int width;
 	int height;
+	int samples;
 
-	if (!PyArg_ParseTuple(args, "ii:offscreen_create", &width, &height))
+	samples = 0;
+	if (!PyArg_ParseTuple(args, "ii|i:offscreen_create", &width, &height, &samples))
 		return NULL;
 
 	return PyObject_CallObject((PyObject *) &PyRASOffScreen_Type, args);
diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h
index d1caf14..0acf1bb 100644
--- a/source/gameengine/Rasterizer/RAS_IOffScreen.h
+++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h
@@ -48,16 +48,19 @@ class RAS_IOffScreen
 public:
 	int		m_width;
 	int     m_height;
+	int	    m_samples;
 
 	virtual ~RAS_IOffScreen() {}
 
-	virtual bool Create(int width, int height) = 0;
+	virtual bool Create(int width, int height, int samples) = 0;
 	virtual void Destroy() = 0;
 	virtual void Bind() = 0;
+	virtual void Blit() = 0;
 	virtual void Unbind() = 0;
 
 	virtual int GetWidth() { return m_width; }
 	virtual int GetHeight() { return m_height; }
+	virtual int GetSamples() { return m_samples; }
 };
 
 #ifdef WITH_PYTHON
diff --git a/source/gameengine/Rasterizer/RAS_IRasterizer.h b/source/gameengine/Rasterizer/RAS_IRasterizer.h
index 72242bb..062795c 100644
--- a/source/gameengine/Rasterizer/RAS_IRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_IRasterizer.h
@@ -262,7 +262,7 @@ public:
 	 * Create an offscreen render buffer that can be used as target for render.
 	 * For the time being, it is only used in VideoTexture for custom render.
 	 */
-	virtual RAS_IOffScreen *CreateOffScreen(int width, int height) = 0;
+	virtual RAS_IOffScreen *CreateOffScreen(int width, int height, int samples) = 0;
 
 	/**
 	 * SwapBuffers swaps the back buffer with the front buffer.
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
index 0585637..bde6764 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp
@@ -33,10 +33,11 @@
 #include "RAS_ICanvas.h"
 
 RAS_OpenGLOffScreen::RAS_OpenGLOffScreen(RAS_ICanvas *canvas)
-    :m_ofs(NULL), m_canvas(canvas), m_bound(false)
+    :m_ofs(NULL), m_canvas(canvas), m_blitfbo(0), m_blittex(0), m_bound(false)
 {
 	m_width = 0;
 	m_height = 0;
+	m_samples = 0;
 }
 
 RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen()
@@ -44,9 +45,10 @@ RAS_OpenGLOffScreen::~RAS_OpenGLOffScreen()
 	Destroy();
 }
 
-bool RAS_OpenGLOffScreen::Create(int width, int height)
+bool RAS_OpenGLOffScreen::Create(int width, int height, int samples)
 {
 	char err_out[256];
+	GLenum status;
 
 	if (m_ofs)
 	{
@@ -54,7 +56,7 @@ bool RAS_OpenGLOffScreen::Create(int width, int height)
 		return false;
 	}
 
-	m_ofs = GPU_offscreen_create(width, height, 0, err_out);
+	m_ofs = GPU_offscreen_create(width, height, samples, err_out);
 	if (m_ofs == NULL)
 	{
 		printf("RAS_OpenGLOffScreen::Create(): failed creating an offscreen buffer (%s)\n", err_out);
@@ -62,7 +64,48 @@ bool RAS_OpenGLOffScreen::Create(int width, int height)
 	}
 	m_width = width;
 	m_height = height;
+
+	if (GPU_offscreen_color_target(m_ofs) == GL_TEXTURE_2D_MULTISAMPLE)
+	{
+		GLuint blit_tex;
+		GLuint blit_fbo;
+		// create a secondary FBO to blit to before the pixel can be read
+
+		/* create texture for new 'fbo_blit' */
+		glGenTextures(1, &blit_tex);
+		if (!blit_tex) {
+			printf("RAS_OpenGLOffScreen::Create(): failed creating a texture for multi-sample offscreen buffer\n");
+			goto L_ERROR;
+		}
+		m_blittex = blit_tex;
+		glBindTexture(GL_TEXTURE_2D, m_blittex);
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+
+		/* write into new single-sample buffer */
+		glGenFramebuffersEXT(1, &blit_fbo);
+		if (!blit_fbo) {
+			printf("RAS_OpenGLOffScreen::Create(): failed creating a FBO for multi-sample offscreen buffer\n");
+			goto L_ERROR;
+		}
+		m_blitfbo = blit_fbo;
+		glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m_blitfbo);
+		glFramebufferTexture2DEXT(
+		        GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+		        GL_TEXTURE_2D, m_blittex, 0);
+		status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+		if (status != GL_FRAMEBUFFER_COMPLETE) {
+			goto L_ERROR;
+		}
+		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+		glBindTexture(GL_TEXTURE_2D, 0);
+		// remember that multisample is enabled
+		m_samples = 1;
+	}
 	return true;
+
+   L_ERROR:
+	Destroy();
+	return false;
 }
 
 void RAS_OpenGLOffScreen::Destroy()
@@ -73,8 +116,21 @@ void RAS_OpenGLOffScreen::Destroy()
 		GPU_offscreen_free(m_ofs);
 		m_ofs = NULL;
 	}
+	if (m_blittex)
+	{
+		GLuint tex = m_blittex;
+		glDeleteTextures(1, &tex);
+		m_blittex = 0;
+	}
+	if (m_blitfbo)
+	{
+		GLuint fbo = m_blitfbo;
+		glDeleteFramebuffersEXT(1, &fbo);
+		m_blitfbo = 0;
+	}
 	m_width = 0;
 	m_height = 0;
+	m_samples = 0;
 }
 
 void RAS_OpenGLOffScreen::Bind()
@@ -95,3 +151,17 @@ void RAS_OpenGLOffScreen::Unbind()
 	}
 }
 
+void RAS_OpenGLOffScreen::Blit()
+{
+	if (m_bound && m_blitfbo)
+	{
+		// set the draw target to the secondary FBO, the read target is still the multisample FBO
+		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_blitfbo);
+
+		// sample the primary
+		glBlitFramebufferEXT(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+		// make sur the next glReadPixels will read from the secondary buffer
+		glBindFramebuffer(GL_READ_FRAMEBUFFER, m_blitfbo);
+	}
+}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
index 8494e99..63ac02f 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h
@@ -34,14 +34,17 @@ class RAS_OpenGLOffScreen : public RAS_IOffScreen
 {
 	GPUOffScreen *m_ofs;
 	RAS_ICanvas *m_canvas;
+	unsigned int m_blitfbo;
+	unsigned int m_blittex;
 	bool m_bound;
 
 public:
 	RAS_OpenGLOffScreen(RAS_ICanvas *canvas);
 	~RAS_OpenGLOffScreen();
 
-	bool Create(int width, int height);
+	bool Create(int width, int height, int samples);
 	void Destroy();
 	void Bind();
+	void Blit();
 	void Unbind();
 };
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 6dff495..18913f6 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -609,13 +609,13 @@ float RAS_OpenGLRasterizer::GetFocalLength()
 	return m_focallength;
 }
 
-RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height)
+RAS_IOffScreen *RAS_OpenGLRasterizer::CreateOffScreen(int width, int height, int samples)
 {
 	RAS_IOffScreen *ofs;
 
 	ofs = new RAS_OpenGLOffScreen(m_2DCanvas);
 
-	if (!ofs->Create(width, height))
+	if (!ofs->Create(width, height, samples))
 	{
 		delete ofs;
 		return NULL;
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
index 55e67a8..44eaeae 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.h
@@ -183,7 +183,7 @@ public:
 	virtual float GetEyeSeparation();
 	virtual void SetFocalLength(const float focallength);
 	virtual float GetFocalLength();
-	virtual RAS_IOffScreen *CreateOffScreen(int width, int height);
+	virtual RAS_IOffScreen *Cre

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list