Commit 6d660851 authored by H. Verbeet's avatar H. Verbeet Committed by Alexandre Julliard

wined3d: Add FBO support for offscreen rendering.

parent ad4c2bdb
...@@ -5985,7 +5985,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) { ...@@ -5985,7 +5985,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
checkGLcall("glFlush"); checkGLcall("glFlush");
TRACE("End Scene\n"); TRACE("End Scene\n");
if(This->renderTarget != NULL) { /* If we're using FBOs this isn't needed */
if (wined3d_settings.offscreen_rendering_mode != ORM_FBO && This->renderTarget != NULL) {
/* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */ /* If the container of the rendertarget is a texture then we need to save the data from the pbuffer */
IUnknown *targetContainer = NULL; IUnknown *targetContainer = NULL;
...@@ -6989,6 +6990,66 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice ...@@ -6989,6 +6990,66 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice
return WINED3D_OK; return WINED3D_OK;
} }
static void bind_fbo(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
if (!This->fbo) {
GL_EXTCALL(glGenFramebuffersEXT(1, &This->fbo));
checkGLcall("glGenFramebuffersEXT()");
}
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, This->fbo));
checkGLcall("glBindFramebuffer()");
}
/* TODO: Handle stencil attachments */
static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
bind_fbo(iface);
if (depth_stencil_impl) {
IWineD3DSurface_PreLoad(depth_stencil);
glBindTexture (GL_TEXTURE_2D, depth_stencil_impl->glDescription.textureName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depth_stencil_impl->glDescription.textureName, 0));
checkGLcall("glFramebufferTexture2DEXT()");
} else {
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
checkGLcall("glFramebufferTexture2DEXT()");
}
if (!This->render_offscreen) {
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
checkGLcall("glBindFramebuffer()");
}
}
static void set_render_target_fbo(IWineD3DDevice *iface, IWineD3DSurface *render_target) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
if (This->render_offscreen) {
bind_fbo(iface);
IWineD3DSurface_PreLoad(render_target);
glBindTexture (GL_TEXTURE_2D, rtimpl->glDescription.textureName);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, rtimpl->glDescription.textureName, 0));
checkGLcall("glFramebufferTexture2DEXT()");
} else {
GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
checkGLcall("glBindFramebuffer()");
}
}
/* internal static helper functions */ /* internal static helper functions */
static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface, static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
IWineD3DSurface *RenderSurface); IWineD3DSurface *RenderSurface);
...@@ -7040,6 +7101,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, ...@@ -7040,6 +7101,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface,
implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
stencil buffer and incure an extra memory overhead */ stencil buffer and incure an extra memory overhead */
hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget); hr = IWineD3DDeviceImpl_ActiveRender(iface, pRenderTarget);
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
set_render_target_fbo(iface, pRenderTarget);
}
} }
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
...@@ -7086,6 +7150,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice * ...@@ -7086,6 +7150,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *
/** TODO: glEnable/glDisable on depth/stencil depending on /** TODO: glEnable/glDisable on depth/stencil depending on
* pNewZStencil is NULL and the depth/stencil is enabled in d3d * pNewZStencil is NULL and the depth/stencil is enabled in d3d
**********************************************************/ **********************************************************/
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
set_depth_stencil_fbo(iface, pNewZStencil);
}
} }
return hr; return hr;
......
...@@ -791,6 +791,12 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) { ...@@ -791,6 +791,12 @@ BOOL IWineD3DImpl_FillGLCaps(IWineD3D *iface, Display* display) {
wined3d_settings.nonpower2_mode = NP2_NONE; wined3d_settings.nonpower2_mode = NP2_NONE;
} }
/* We can only use ORM_FBO when the hardware supports it. */
if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && !gl_info->supported[EXT_FRAMEBUFFER_OBJECT]) {
WARN_(d3d_caps)("GL_EXT_framebuffer_object not supported, falling back to PBuffer offscreen rendering mode.\n");
wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
}
/* Below is a list of Nvidia and ATI GPUs. Both vendors have dozens of different GPUs with roughly the same /* Below is a list of Nvidia and ATI GPUs. Both vendors have dozens of different GPUs with roughly the same
* features. In most cases GPUs from a certain family differ in clockspeeds, the amount of video memory and * features. In most cases GPUs from a certain family differ in clockspeeds, the amount of video memory and
* in case of the latest videocards in the number of pixel/vertex pipelines. * in case of the latest videocards in the number of pixel/vertex pipelines.
......
...@@ -2078,6 +2078,16 @@ static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) { ...@@ -2078,6 +2078,16 @@ static void drawPrimitiveUploadTextures(IWineD3DDeviceImpl* This) {
} }
} }
static void check_fbo_status(IWineD3DDevice *iface) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
GLenum status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
switch(status) {
case GL_FRAMEBUFFER_COMPLETE_EXT: TRACE("FBO complete.\n"); break;
default: TRACE("FBO status %#x.\n", status); break;
}
}
/* Routine common to the draw primitive and draw indexed primitive routines */ /* Routine common to the draw primitive and draw indexed primitive routines */
void drawPrimitive(IWineD3DDevice *iface, void drawPrimitive(IWineD3DDevice *iface,
int PrimitiveType, int PrimitiveType,
...@@ -2101,6 +2111,10 @@ void drawPrimitive(IWineD3DDevice *iface, ...@@ -2101,6 +2111,10 @@ void drawPrimitive(IWineD3DDevice *iface,
BOOL lighting_changed, lighting_original = FALSE; BOOL lighting_changed, lighting_original = FALSE;
if (TRACE_ON(d3d_draw) && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
check_fbo_status(iface);
}
/* Shaders can be implemented using ARB_PROGRAM, GLSL, or software - /* Shaders can be implemented using ARB_PROGRAM, GLSL, or software -
* here simply check whether a shader was set, or the user disabled shaders */ * here simply check whether a shader was set, or the user disabled shaders */
if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader && if (This->vs_selected_mode != SHADER_NONE && This->stateBlock->vertexShader &&
......
...@@ -215,6 +215,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) ...@@ -215,6 +215,11 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
TRACE("Using PBuffers for offscreen rendering\n"); TRACE("Using PBuffers for offscreen rendering\n");
wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER; wined3d_settings.offscreen_rendering_mode = ORM_PBUFFER;
} }
else if (!strcmp(buffer,"fbo"))
{
TRACE("Using FBOs for offscreen rendering\n");
wined3d_settings.offscreen_rendering_mode = ORM_FBO;
}
} }
if ( !get_config_key( hkey, appkey, "RenderTargetLockMode", buffer, size) ) if ( !get_config_key( hkey, appkey, "RenderTargetLockMode", buffer, size) )
{ {
......
...@@ -137,6 +137,7 @@ static WINED3DGLTYPE const glTypeLookup[WINED3DDECLTYPE_UNUSED] = { ...@@ -137,6 +137,7 @@ static WINED3DGLTYPE const glTypeLookup[WINED3DDECLTYPE_UNUSED] = {
#define ORM_BACKBUFFER 0 #define ORM_BACKBUFFER 0
#define ORM_PBUFFER 1 #define ORM_PBUFFER 1
#define ORM_FBO 2
#define SHADER_SW 0 #define SHADER_SW 0
#define SHADER_ARB 1 #define SHADER_ARB 1
...@@ -550,6 +551,7 @@ typedef struct IWineD3DDeviceImpl ...@@ -550,6 +551,7 @@ typedef struct IWineD3DDeviceImpl
/* For rendering to a texture using glCopyTexImage */ /* For rendering to a texture using glCopyTexImage */
BOOL render_offscreen; BOOL render_offscreen;
GLuint fbo;
/* Cursor management */ /* Cursor management */
BOOL bCursorVisible; BOOL bCursorVisible;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment