[WINED3D] Pbuffer/ActiveRender cleanup #2
Ivan Gyurdiev
ivg231 at gmail.com
Sun Sep 17 05:24:59 CDT 2006
This patch should be a no-op in functionality (mostly).
Reports of upside-down rendering caused by the last cleanup should be
resolved here.
The patch is large, but all of it's related functionality.
Changelog:
===========
- break up functionality in ActiveRender into separate functions
- change current device_reapply_stateblock() function to
device_switch_render_context(), which is really what we're trying to do
(that's why we reapply the stateblock). Move the glXMakeCurrent call here.
- add function device_render_onscreen()
- break up pbuffer functionality in ActiveRender into separate
functions. Split into:
- device_pbuffer_find_context (previously FindGLContext)
- device_pbuffer_init_context (previously "This really should be
in FindGLContext")
- device_pbuffer_render_offscreen (makes use of above two and
device_switch_render_context())
- remove GL_VERSION_1_3 check
- it's wrong, should be GLX_VERSION_1_3
- my last cleanup moved code outside the ifdef by accident, and
nobody has complained.
- it's being replaced here with proper extension support:
SGIX_PBUFFER, SGIX_FBCONFIG. It's been noted that ATI doesn't support
this properly. Given the number of things ATI doesn't support properly
(glXDestroyPbuffer?), I don't think ATI pbuffer support should be
maintained - should use FBOs for ATI, until their drivers are fixed.
- rename render_to_texture to render_upside_down, and make sure to call
it in the case of offscreen rendering where pbuffers are not supported [
see EndScene to see what makes the render flip necessary - it is not
conditional on pbuffer_support ].
-------------- next part --------------
---
dlls/wined3d/device.c | 540 +++++++++++++++++++++-------------------
dlls/wined3d/directx.c | 27 ++
dlls/wined3d/utils.c | 4
dlls/wined3d/wined3d_private.h | 9 +
include/wine/wined3d_gl.h | 41 +++
5 files changed, 360 insertions(+), 261 deletions(-)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 34026db..f9e23cf 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -7202,7 +7202,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl
}
-#ifdef GL_VERSION_1_3
/* Internal functions not in DirectX */
/** TODO: move this off to the opengl context manager
*(the swapchain doesn't need to know anything about offscreen rendering!)
@@ -7222,76 +7221,31 @@ static HRESULT WINAPI IWineD3DDeviceImpl
return WINED3D_OK;
}
-/* TODO: move this off into a context manager so that GLX_ATI_render_texture and other types of surface can be used. */
-static HRESULT WINAPI IWineD3DDeviceImpl_FindGLContext(IWineD3DDevice *iface, IWineD3DSurface *pSurface, glContext **context) {
- IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
- int i;
- unsigned int width;
- unsigned int height;
- WINED3DFORMAT format;
- WINED3DSURFACE_DESC surfaceDesc;
- memset(&surfaceDesc, 0, sizeof(surfaceDesc));
- surfaceDesc.Width = &width;
- surfaceDesc.Height = &height;
- surfaceDesc.Format = &format;
- IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
- *context = NULL;
- /* I need a get width/height function (and should do something with the format) */
- for (i = 0; i < CONTEXT_CACHE; ++i) {
- /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
- ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
- the pSurface can be set to 0 allowing it to be reused from cache **/
- if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
- && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
- *context = &This->contextCache[i];
- break;
- }
- if (This->contextCache[i].Width == 0) {
- This->contextCache[i].pSurface = pSurface;
- This->contextCache[i].Width = width;
- This->contextCache[i].Height = height;
- *context = &This->contextCache[i];
- break;
- }
- }
- if (i == CONTEXT_CACHE) {
- int minUsage = 0x7FFFFFFF; /* MAX_INT */
- glContext *dropContext = 0;
- for (i = 0; i < CONTEXT_CACHE; i++) {
- if (This->contextCache[i].usedcount < minUsage) {
- dropContext = &This->contextCache[i];
- minUsage = This->contextCache[i].usedcount;
- }
- }
- /* clean up the context (this doesn't work for ATI at the moment */
-#if 0
- glXDestroyContext(swapchain->display, dropContext->context);
- glXDestroyPbuffer(swapchain->display, dropContext->drawable);
-#endif
- FIXME("Leak\n");
- dropContext->Width = 0;
- dropContext->pSurface = pSurface;
- *context = dropContext;
- } else {
- if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
- for (i = 0; i < CONTEXT_CACHE; i++) {
- This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
- }
- }
- }
- if (*context != NULL)
- return WINED3D_OK;
- else
- return E_OUTOFMEMORY;
-}
-#endif
-
-/* Reapply the device stateblock */
-static void device_reapply_stateblock(IWineD3DDeviceImpl* This) {
+/**********************************************************
+ * Device (rendering) helper functions follow.
+ **********************************************************/
- BOOL oldRecording;
+/* Switch the rendering context for the current render target. */
+static void device_switch_render_context(
+ IWineD3DDeviceImpl* This,
+ IWineD3DSwapChain* currentSwapchain,
+ Display* display,
+ GLXDrawable drawable,
+ GLXContext context) {
+
+ BOOL oldRecording;
IWineD3DStateBlockImpl *oldUpdateStateBlock;
+ IWineD3DSwapChainImpl *currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
+ /* Change rendering context */
+ if (glXMakeCurrent(display, drawable, context) == False) {
+ ERR("Error in setting current context: context %p drawable %ld !\n", context, drawable);
+ return;
+ }
+
+ /* Clean the old render context */
+ IWineD3DDeviceImpl_CleanRender((IWineD3DDevice*) This, currentSwapchainImpl);
+
/* Disable recording */
oldUpdateStateBlock = This->updateStateBlock;
oldRecording= This->isRecordingState;
@@ -7306,10 +7260,8 @@ static void device_reapply_stateblock(IW
This->updateStateBlock = oldUpdateStateBlock;
}
-/* Set the device to render to a texture, or not.
- * This involves changing renderUpsideDown */
-
-static void device_render_to_texture(IWineD3DDeviceImpl* This, BOOL isTexture) {
+/* Set the device to render upside down */
+static void device_render_upside_down(IWineD3DDeviceImpl* This, BOOL upsideDown) {
DWORD cullMode;
BOOL oldRecording;
@@ -7323,7 +7275,7 @@ static void device_render_to_texture(IWi
/* Set upside-down rendering, and update the cull mode */
/* The surface must be rendered upside down to cancel the flip produced by glCopyTexImage */
- This->renderUpsideDown = isTexture;
+ This->renderUpsideDown = upsideDown;
This->last_was_rhw = FALSE;
This->proj_valid = FALSE;
IWineD3DDevice_GetRenderState((IWineD3DDevice*) This, WINED3DRS_CULLMODE, &cullMode);
@@ -7334,15 +7286,52 @@ static void device_render_to_texture(IWi
This->updateStateBlock = oldUpdateStateBlock;
}
+static void device_render_onscreen(
+ IWineD3DDeviceImpl *This,
+ IWineD3DSwapChain *currentSwapchain,
+ IWineD3DSwapChain *renderSurfaceSwapchain,
+ IWineD3DSurface *renderSurface) {
+
+ IWineD3DSwapChainImpl* renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
+
+ BOOL backbuf = FALSE;
+ int i;
+
+ /* We also need to make sure that the lights &co are also in the context of the swapchains */
+ /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
+ for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
+ if(renderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
+ backbuf = TRUE;
+ break;
+ }
+ }
+ if (backbuf) {
+ } else {
+ /* This could be flagged so that some operations work directly with the front buffer */
+ FIXME("Attempting to set the renderTarget to the frontBuffer\n");
+ }
+
+ /* Change rendering context */
+ device_switch_render_context(This, currentSwapchain,
+ renderSurfaceSwapchainImpl->display,
+ renderSurfaceSwapchainImpl->win,
+ renderSurfaceSwapchainImpl->glCtx);
+
+ return;
+}
+
+/***********************************************************
+ * PBuffer helper functions follow
+ ***********************************************************/
+
/* Returns an array of compatible FBconfig(s).
* The array must be freed with XFree. Requires ENTER_GL() */
-static GLXFBConfig* device_find_fbconfigs(
+static GLXFBConfigSGIX* device_pbuffer_find_fbconfigs(
IWineD3DDeviceImpl* This,
- IWineD3DSwapChainImpl* implicitSwapchainImpl,
IWineD3DSurface* RenderSurface) {
- GLXFBConfig* cfgs = NULL;
+ GLXFBConfigSGIX* cfgs = NULL;
int nCfgs = 0;
int attribs[256];
int nAttribs = 0;
@@ -7350,6 +7339,8 @@ static GLXFBConfig* device_find_fbconfig
IWineD3DSurface *StencilSurface = This->stencilBufferTarget;
D3DFORMAT BackBufferFormat = ((IWineD3DSurfaceImpl *) RenderSurface)->resource.format;
D3DFORMAT StencilBufferFormat = (NULL != StencilSurface) ? ((IWineD3DSurfaceImpl *) StencilSurface)->resource.format : 0;
+ IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+ IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
/**TODO:
if StencilSurface == NULL && zBufferTarget != NULL then switch the zbuffer off,
@@ -7361,16 +7352,17 @@ #define PUSH2(att,value) attribs[nAttri
/* PUSH2(GLX_BIND_TO_TEXTURE_RGBA_ATI, True); examples of this are few and far between (but I've got a nice working one!)*/
- PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
- PUSH2(GLX_X_RENDERABLE, TRUE);
+ PUSH2(GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT);
+ PUSH2(GLX_X_RENDERABLE_SGIX, TRUE);
PUSH2(GLX_DOUBLEBUFFER, TRUE);
TRACE("calling makeglcfg\n");
D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, FALSE /* alternate */);
PUSH1(None);
TRACE("calling chooseFGConfig\n");
- cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
+ cfgs = GL_EXTCALL(glXChooseFBConfigSGIX(implicitSwapchainImpl->display,
DefaultScreen(implicitSwapchainImpl->display),
- attribs, &nCfgs);
+ attribs, &nCfgs));
+
if (cfgs == NULL) {
/* OK we didn't find the exact config, so use any reasonable match */
/* TODO: fill in the 'requested' and 'current' depths, also make sure that's
@@ -7378,16 +7370,16 @@ #define PUSH2(att,value) attribs[nAttri
MESSAGE("Failed to find exact match, finding alternative but you may "
"suffer performance issues, try changing xfree's depth to match the requested depth\n");
nAttribs = 0;
- PUSH2(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT);
- /* PUSH2(GLX_X_RENDERABLE, TRUE); */
- PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
+ PUSH2(GLX_DRAWABLE_TYPE_SGIX, GLX_PBUFFER_BIT_SGIX | GLX_WINDOW_BIT_SGIX);
+ /* PUSH2(GLX_X_RENDERABLE_SGIX, TRUE); */
+ PUSH2(GLX_RENDER_TYPE_SGIX, GLX_RGBA_BIT_SGIX);
PUSH2(GLX_DOUBLEBUFFER, FALSE);
TRACE("calling makeglcfg\n");
D3DFmtMakeGlCfg(BackBufferFormat, StencilBufferFormat, attribs, &nAttribs, TRUE /* alternate */);
PUSH1(None);
- cfgs = glXChooseFBConfig(implicitSwapchainImpl->display,
+ cfgs = GL_EXTCALL(glXChooseFBConfigSGIX(implicitSwapchainImpl->display,
DefaultScreen(implicitSwapchainImpl->display),
- attribs, &nCfgs);
+ attribs, &nCfgs));
}
if (cfgs == NULL) {
@@ -7423,201 +7415,231 @@ #undef PUSH2
return cfgs;
}
-/** FIXME: This is currently used called whenever SetRenderTarget or SetStencilBuffer are called
-* the functionality needs splitting up so that we don't do more than we should do.
-* this only seems to impact performance a little.
- ******************************/
+static HRESULT device_pbuffer_find_context(
+ IWineD3DDeviceImpl *This,
+ IWineD3DSurface *pSurface,
+ glContext **newContext) {
+
+ int i;
+ unsigned int width;
+ unsigned int height;
+ WINED3DFORMAT format;
+ WINED3DSURFACE_DESC surfaceDesc;
+ glContext* context = NULL;
+
+ /* Fetch some information about this surface */
+ memset(&surfaceDesc, 0, sizeof(surfaceDesc));
+ surfaceDesc.Width = &width;
+ surfaceDesc.Height = &height;
+ surfaceDesc.Format = &format;
+ IWineD3DSurface_GetDesc(pSurface, &surfaceDesc);
+
+ /* Look for the context in the context cache */
+ for (i = 0; i < CONTEXT_CACHE; ++i) {
+
+ /** NOTE: the contextCache[i].pSurface == pSurface check ceates onepbuffer per surface
+ * ATI cards don't destroy pbuffers, but as soon as resource releasing callbacks are inplace
+ * the pSurface can be set to 0 allowing it to be reused from cache **/
+
+ /* I need a get width/height function (and should do something with the format) */
+ if (This->contextCache[i].Width == width && This->contextCache[i].Height == height
+ && (pbuffer_per_surface == FALSE || This->contextCache[i].pSurface == pSurface || This->contextCache[i].pSurface == NULL)) {
+ context = &This->contextCache[i];
+ break;
+ }
+
+ if (This->contextCache[i].Width == 0) {
+ This->contextCache[i].pSurface = pSurface;
+ This->contextCache[i].Width = width;
+ This->contextCache[i].Height = height;
+ context = &This->contextCache[i];
+ break;
+ }
+ }
+
+ /* Not found: evict another context from the cache */
+ if (i == CONTEXT_CACHE) {
+ int minUsage = 0x7FFFFFFF; /* MAX_INT */
+ glContext *dropContext = 0;
+ for (i = 0; i < CONTEXT_CACHE; i++) {
+ if (This->contextCache[i].usedcount < minUsage) {
+ dropContext = &This->contextCache[i];
+ minUsage = This->contextCache[i].usedcount;
+ }
+ }
+ /* clean up the context (this doesn't work for ATI at the moment */
+#if 0
+ glXDestroyContext(swapchain->display, dropContext->context);
+ GL_EXTCALL(glXDestroyGLXPbufferSGIX(swapchain->display, dropContext->drawable));
+#endif
+ FIXME("Leak\n");
+ dropContext->Width = 0;
+ dropContext->pSurface = pSurface;
+ context = dropContext;
+
+ /* Found in the cache */
+ } else {
+ if (++This->contextCache[i].usedcount == 0x7FFFFFFF /* MAX_INT */ - 1 ) {
+ for (i = 0; i < CONTEXT_CACHE; i++)
+ This->contextCache[i].usedcount = max(0, This->contextCache[i].usedcount - (0x7FFFFFFF /* MAX_INT */ >> 1));
+ }
+ }
+
+ if (context == NULL)
+ goto err;
+
+ *newContext = context;
+ return WINED3D_OK;
+
+ err:
+ return E_FAIL;
+}
+
+static HRESULT device_pbuffer_init_context(
+ IWineD3DDeviceImpl* This,
+ IWineD3DSurface* renderSurface,
+ glContext* context) {
+
+ XVisualInfo *visinfo = NULL;
+ GLXFBConfigSGIX *cfgs = NULL;
+
+ IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+ IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
+
+ /* Already initialized, do nothing */
+ if (context->context != NULL)
+ goto exit;
+
+ /* Try fo find a valid fbconfig for this surface */
+ cfgs = device_pbuffer_find_fbconfigs(This, renderSurface);
+ if (!cfgs)
+ goto err;
+
+ /* Create a new pbuffer, set drawable field */
+ context->drawable = GL_EXTCALL(glXCreateGLXPbufferSGIX(
+ implicitSwapchainImpl->display, cfgs[0], context->Width, context->Height, NULL));
+
+ /* Find a visual */
+ visinfo = GL_EXTCALL(glXGetVisualFromFBConfigSGIX(implicitSwapchainImpl->display, cfgs[0]));
+ if (visinfo == NULL) {
+ ERR("Error: couldn't get an RGBA, double-buffered visual\n");
+ goto err;
+ }
+
+ /* Create context from visual, set context field */
+ context->context = glXCreateContext(
+ implicitSwapchainImpl->display, visinfo, implicitSwapchainImpl->glCtx, GL_TRUE);
+ if (context->context == NULL) {
+ ERR("(%p) : Failed to create GLX context for surface %p\n", This, renderSurface);
+ goto err;
+ }
+
+ exit:
+ if (cfgs != NULL) XFree(cfgs);
+ if (visinfo != NULL) XFree(visinfo);
+ return WINED3D_OK;
+
+ err:
+ if (cfgs != NULL) XFree(cfgs);
+ if (visinfo != NULL) XFree(visinfo);
+ return E_FAIL;
+}
+
+static void device_pbuffer_render_offscreen(
+ IWineD3DDeviceImpl* This,
+ IWineD3DSwapChain* currentSwapchain,
+ IWineD3DSurface* initialRenderTarget) {
+
+ /***********************************************************************
+ * This is a quickly hacked out implementation of offscreen textures.
+ * It will work in most cases but there may be problems if the client
+ * modifies the texture directly, or expects the contents of the rendertarget
+ * to be persistent.
+ *
+ * There are some real speed vs compatibility issues here:
+ * we should really use a new context for every texture, but that eats ram.
+ * we should also be restoring the texture to the pbuffer but that eats CPU
+ * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
+ * but if this means reusing the display backbuffer then we need to make sure that
+ * states are correctly preserved.
+ * In many cases I would expect that we can 'skip' some functions, such as preserving states,
+ * and gain a good performance increase at the cost of compatibility.
+ * I would suggest that, when this is the case, a user configurable flag be made
+ * available, allowing the user to choose the best emulated experience for them.
+ *********************************************************************/
+
+ IWineD3DSwapChain *implicitSwapchain = This->swapchains[0];
+ IWineD3DSwapChainImpl *implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
+
+ glContext *newContext;
+
+ TRACE("Switching to offscreen rendering.\n");
+
+ /* Here were using a shared context model */
+ if (device_pbuffer_find_context(This, initialRenderTarget, &newContext) != WINED3D_OK) {
+ FIXME("(%p) : Failed to find a context for surface %p\n", This, initialRenderTarget);
+ return;
+ }
+
+ if (device_pbuffer_init_context(This, initialRenderTarget, newContext) != WINED3D_OK) {
+ FIXME("(%p) : Failed to initialize a context for surface %p\n", This, initialRenderTarget);
+ return;
+ }
+
+ /* Change rendering context */
+ device_switch_render_context(This, currentSwapchain,
+ implicitSwapchainImpl->display, newContext->drawable, newContext->context);
+
+ implicitSwapchainImpl->render_ctx = newContext->context;
+ implicitSwapchainImpl->drawable = newContext->drawable;
+}
+
static HRESULT WINAPI IWineD3DDeviceImpl_ActiveRender(IWineD3DDevice* iface,
IWineD3DSurface *RenderSurface) {
- /**
- * Currently only active for GLX >= 1.3
- * for others versions we'll have to use GLXPixmaps
- *
- * normally we must test GLX_VERSION_1_3 but nvidia headers are not correct
- * as they implement GLX 1.3 but only define GLX_VERSION_1_2
- * so only check OpenGL version
- * ..........................
- * I don't believe that it is a problem with NVidia headers,
- * XFree only supports GLX1.2, nVidia (and ATI to some extent) provide 1.3 functions
- * in GLX 1.2, there is no mention of the correct way to tell if the extensions are provided.
- * ATI Note:
- * Your application will report GLX version 1.2 on glXQueryVersion.
- * However, it is safe to call the GLX 1.3 functions as described below.
- */
-#if defined(GL_VERSION_1_3)
-
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
- IWineD3DSurface *tmp;
- GLXFBConfig* cfgs = NULL;
- IWineD3DSwapChain *currentSwapchain;
- IWineD3DSwapChainImpl *currentSwapchainImpl;
- IWineD3DSwapChain *implicitSwapchain;
- IWineD3DSwapChainImpl *implicitSwapchainImpl;
- IWineD3DSwapChain *renderSurfaceSwapchain;
- IWineD3DSwapChainImpl *renderSurfaceSwapchainImpl;
-
- /* Obtain a reference to the device implicit swapchain,
- * the swapchain of the current render target,
+ BOOL offscreenRendering = FALSE;
+ IWineD3DSwapChain *currentSwapchain;
+ IWineD3DSwapChain *renderSurfaceSwapchain;
+
+ /* Obtain a reference to the swapchain of the current render target,
* and the swapchain of the new render target.
* Fallback to device implicit swapchain if the current render target doesn't have one */
- IWineD3DDevice_GetSwapChain(iface, 0, &implicitSwapchain);
IWineD3DSurface_GetContainer(RenderSurface, &IID_IWineD3DSwapChain, (void**) &renderSurfaceSwapchain);
IWineD3DSurface_GetContainer(This->renderTarget, &IID_IWineD3DSwapChain, (void **)¤tSwapchain);
if (currentSwapchain == NULL)
IWineD3DDevice_GetSwapChain(iface, 0, ¤tSwapchain);
- currentSwapchainImpl = (IWineD3DSwapChainImpl*) currentSwapchain;
- implicitSwapchainImpl = (IWineD3DSwapChainImpl*) implicitSwapchain;
- renderSurfaceSwapchainImpl = (IWineD3DSwapChainImpl*) renderSurfaceSwapchain;
+ offscreenRendering = (renderSurfaceSwapchain == NULL);
ENTER_GL();
- /**
- * TODO: remove the use of IWineD3DSwapChainImpl, a context manager will help since it will replace the
- * renderTarget = swapchain->backBuffer[i] bit and anything to do with *glContexts
- **********************************************************************/
- if (renderSurfaceSwapchain != NULL) {
-
- /* We also need to make sure that the lights &co are also in the context of the swapchains */
- /* FIXME: If the render target gets sent to the frontBuffer should be be presenting it raw? */
- TRACE("making swapchain active\n");
- if (RenderSurface != This->renderTarget) {
- BOOL backbuf = FALSE;
- int i;
+ /* Onscreen rendering */
+ if (!offscreenRendering) {
+ device_render_onscreen (This, currentSwapchain, renderSurfaceSwapchain, RenderSurface);
+ device_render_upside_down(This, FALSE);
- for(i = 0; i < renderSurfaceSwapchainImpl->presentParms.BackBufferCount; i++) {
- if(RenderSurface == renderSurfaceSwapchainImpl->backBuffer[i]) {
- backbuf = TRUE;
- break;
- }
- }
-
- if (backbuf) {
- } else {
- /* This could be flagged so that some operations work directly with the front buffer */
- FIXME("Attempting to set the renderTarget to the frontBuffer\n");
- }
- if (glXMakeCurrent(renderSurfaceSwapchainImpl->display,
- renderSurfaceSwapchainImpl->win,
- renderSurfaceSwapchainImpl->glCtx) == False) {
-
- TRACE("Error in setting current context: context %p drawable %ld !\n",
- implicitSwapchainImpl->glCtx, implicitSwapchainImpl->win);
- }
- checkGLcall("glXMakeContextCurrent");
-
- /* Clean up the old context */
- IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
-
- /* Reapply the stateblock, and set the device not to render to texture */
- device_reapply_stateblock(This);
- device_render_to_texture(This, FALSE);
- }
-
- /* Offscreen rendering: PBuffers (currently disabled).
- * Also note that this path is never reached if FBOs are supported */
- } else if (pbuffer_support &&
- (cfgs = device_find_fbconfigs(This, implicitSwapchainImpl, RenderSurface)) != NULL) {
-
- /** ********************************************************************
- * This is a quickly hacked out implementation of offscreen textures.
- * It will work in most cases but there may be problems if the client
- * modifies the texture directly, or expects the contents of the rendertarget
- * to be persistent.
- *
- * There are some real speed vs compatibility issues here:
- * we should really use a new context for every texture, but that eats ram.
- * we should also be restoring the texture to the pbuffer but that eats CPU
- * we can also 'reuse' the current pbuffer if the size is larger than the requested buffer,
- * but if this means reusing the display backbuffer then we need to make sure that
- * states are correctly preserved.
- * In many cases I would expect that we can 'skip' some functions, such as preserving states,
- * and gain a good performance increase at the cost of compatibility.
- * I would suggest that, when this is the case, a user configurable flag be made
- * available, allowing the user to choose the best emulated experience for them.
- *********************************************************************/
-
- XVisualInfo *visinfo;
- glContext *newContext;
-
- /* Here were using a shared context model */
- if (WINED3D_OK != IWineD3DDeviceImpl_FindGLContext(iface, RenderSurface, &newContext)) {
- FIXME("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
- }
-
- /* If the context doesn't exist then create a new one */
- /* TODO: This should really be part of findGlContext */
- if (NULL == newContext->context) {
-
- int attribs[256];
- int nAttribs = 0;
-
- TRACE("making new buffer\n");
- attribs[nAttribs++] = GLX_PBUFFER_WIDTH;
- attribs[nAttribs++] = newContext->Width;
- attribs[nAttribs++] = GLX_PBUFFER_HEIGHT;
- attribs[nAttribs++] = newContext->Height;
- attribs[nAttribs++] = None;
-
- newContext->drawable = glXCreatePbuffer(implicitSwapchainImpl->display, cfgs[0], attribs);
-
- /** ****************************************
- *GLX1.3 isn't supported by XFree 'yet' until that point ATI emulates pBuffers
- *they note:
- * In future releases, we may provide the calls glXCreateNewContext,
- * glXQueryDrawable and glXMakeContextCurrent.
- * so until then we have to use glXGetVisualFromFBConfig &co..
- ********************************************/
-
- visinfo = glXGetVisualFromFBConfig(implicitSwapchainImpl->display, cfgs[0]);
- if (!visinfo) {
- ERR("Error: couldn't get an RGBA, double-buffered visual\n");
- } else {
- newContext->context = glXCreateContext(
- implicitSwapchainImpl->display, visinfo,
- implicitSwapchainImpl->glCtx, GL_TRUE);
-
- XFree(visinfo);
- }
- }
- if (NULL == newContext || NULL == newContext->context) {
- ERR("(%p) : Failed to find a context for surface %p\n", iface, RenderSurface);
- } else {
- /* Debug logging, (this function leaks), change to a TRACE when the leak is plugged */
- if (glXMakeCurrent(implicitSwapchainImpl->display,
- newContext->drawable, newContext->context) == False) {
-
- TRACE("Error in setting current context: context %p drawable %ld\n",
- newContext->context, newContext->drawable);
- }
- checkGLcall("glXMakeContextCurrent");
-
- /* Clean up the old context */
- IWineD3DDeviceImpl_CleanRender(iface, currentSwapchainImpl);
-
- /* Reapply stateblock, and set device to render to a texture */
- device_reapply_stateblock(This);
- device_render_to_texture(This, TRUE);
+ /* Offscreen rendering: PBuffers */
+ } else if (wined3d_settings.offscreen_selected_mode == OFFSCREEN_PBUFFER) {
+ device_pbuffer_render_offscreen(This, currentSwapchain, This->renderTarget);
+ device_render_upside_down(This, TRUE);
+
+ /* Offscreen rendering will be done onscreen, but result will
+ * still be written to texture afterwards */
+ } else
+ device_render_upside_down(This, TRUE);
- /* Set the current context of the swapchain to the new context */
- implicitSwapchainImpl->drawable = newContext->drawable;
- implicitSwapchainImpl->render_ctx = newContext->context;
- }
- }
+ LEAVE_GL();
/* Replace the render target */
- tmp = This->renderTarget;
+ IWineD3DSurface_AddRef(RenderSurface);
+ IWineD3DSurface_Release(This->renderTarget);
This->renderTarget = RenderSurface;
- IWineD3DSurface_AddRef(This->renderTarget);
- IWineD3DSurface_Release(tmp);
+ This->offscreenRendering = offscreenRendering;
- if (cfgs != NULL) XFree(cfgs);
- if (implicitSwapchain != NULL) IWineD3DSwapChain_Release(implicitSwapchain);
if (currentSwapchain != NULL) IWineD3DSwapChain_Release(currentSwapchain);
if (renderSurfaceSwapchain != NULL) IWineD3DSwapChain_Release(renderSurfaceSwapchain);
- LEAVE_GL();
-#endif
+
return WINED3D_OK;
}
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 19e3172..909b88c 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -237,6 +237,22 @@ static void select_shader_mode(
}
}
+/* Select the offscreen mode, based on the given capabilities */
+static void select_offscreen_mode(
+ WineD3D_GL_Info *gl_info,
+ int* offscreen_selected) {
+
+ /* FBOs currently not supported.
+ * PBUFFERs currently disabled */
+
+ if (FALSE && gl_info->supported[EXT_FRAMEBUFFER_OBJECT])
+ *offscreen_selected = OFFSCREEN_FBO;
+ else if (pbuffer_support && gl_info->glx_supported[SGIX_FBCONFIG] && gl_info->glx_supported[SGIX_PBUFFER])
+ *offscreen_selected = OFFSCREEN_PBUFFER;
+ else
+ *offscreen_selected = OFFSCREEN_NONE;
+}
+
/** Select the number of report maximum shader constants based on the selected shader modes */
void select_shader_max_constants(WineD3D_GL_Info *gl_info) {
@@ -975,6 +991,15 @@ #undef USE_GL_FUNC
}
memcpy(ThisExtn, Start, (GLX_Extensions - Start));
TRACE_(d3d_caps)("- %s\n", ThisExtn);
+
+ if (strcmp(ThisExtn, "GLX_SGIX_pbuffer") == 0) {
+ TRACE_(d3d_caps)(" FOUND: SGIX Pixel Buffer support\n");
+ gl_info->glx_supported[SGIX_PBUFFER] = TRUE;
+ } else if (strcmp(ThisExtn, "GLX_SGIX_fbconfig") == 0) {
+ TRACE_(d3d_caps)(" FOUND: SGIX Framebuffer Config support\n");
+ gl_info->glx_supported[SGIX_FBCONFIG] = TRUE;
+ }
+
if (*GLX_Extensions == ' ') GLX_Extensions++;
}
}
@@ -1810,6 +1835,7 @@ static HRESULT WINAPI IWineD3DImpl_GetDe
}
select_shader_mode(&This->gl_info, DeviceType,
&wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+ select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
select_shader_max_constants(&This->gl_info);
/* ------------------------------------------------
@@ -2400,6 +2426,7 @@ static HRESULT WINAPI IWineD3DImpl_Crea
LEAVE_GL();
select_shader_mode(&This->gl_info, DeviceType,
&wined3d_settings.ps_selected_mode, &wined3d_settings.vs_selected_mode);
+ select_offscreen_mode(&This->gl_info, &wined3d_settings.offscreen_selected_mode);
select_shader_max_constants(&This->gl_info);
temp_result = allocate_shader_constants(object->updateStateBlock);
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 2d072fa..e60b0ee 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -2281,13 +2281,13 @@ #define PUSH2(att,value) attribs[(*nAtt
switch (BackBufferFormat) {
/* color buffer */
case WINED3DFMT_P8:
- PUSH2(GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT);
+ PUSH2(GLX_RENDER_TYPE_SGIX, GLX_COLOR_INDEX_BIT_SGIX);
PUSH2(GLX_BUFFER_SIZE, 8);
PUSH2(GLX_DOUBLEBUFFER, TRUE);
break;
case WINED3DFMT_R3G3B2:
- PUSH2(GLX_RENDER_TYPE, GLX_RGBA_BIT);
+ PUSH2(GLX_RENDER_TYPE_SGIX, GLX_RGBA_BIT_SGIX);
PUSH2(GLX_RED_SIZE, 3);
PUSH2(GLX_GREEN_SIZE, 3);
PUSH2(GLX_BLUE_SIZE, 2);
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9b36a70..1615b56 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -127,6 +127,10 @@ #define VS_SW 2
#define PS_NONE 0
#define PS_HW 1
+#define OFFSCREEN_NONE 0
+#define OFFSCREEN_PBUFFER 1
+#define OFFSCREEN_FBO 2
+
#define VBO_NONE 0
#define VBO_HW 1
@@ -156,6 +160,7 @@ typedef struct wined3d_settings_s {
BOOL glslRequested;
int vs_selected_mode;
int ps_selected_mode;
+ int offscreen_selected_mode;
/* nonpower 2 function */
int nonpower2_mode;
int rendertargetlock_mode;
@@ -188,6 +193,7 @@ #endif
/* GL related defines */
/* ------------------ */
#define GL_SUPPORT(ExtName) (GLINFO_LOCATION.supported[ExtName] != 0)
+#define GLX_SUPPORT(ExtName) (GLINFO_LOCATION.glx_supported[ExtName] != 0)
#define GL_LIMITS(ExtName) (GLINFO_LOCATION.max_##ExtName)
#define GL_EXTCALL(FuncName) (GLINFO_LOCATION.FuncName)
#define GL_VEND(_VendName) (GLINFO_LOCATION.gl_vendor == VENDOR_##_VendName ? TRUE : FALSE)
@@ -543,6 +549,9 @@ #define NEEDS_DI
/* For rendering to a texture using glCopyTexImage */
BOOL renderUpsideDown;
+ /* Offscreen rendering */
+ BOOL offscreenRendering;
+
/* Cursor management */
BOOL bCursorVisible;
UINT xHotSpot;
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 1a589a5..31fa32c 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -1023,6 +1023,7 @@ #define GL_HILO8_NV
#define GL_SIGNED_HILO8_NV 0x885F
#define GL_FORCE_BLUE_TO_ONE_NV 0x8860
#endif
+
/* GL_ATI_texture_env_combine3 */
#ifndef GL_ATI_texture_env_combine3
#define GL_ATI_texture_env_combine3 1
@@ -1305,6 +1306,32 @@ #endif
* defines and functions pointer
****************************************************/
+/* GLX_SGIX_fbconfig */
+#ifndef GLX_SGIX_fbconfig
+#define GLX_SGIX_fbconfig 1
+typedef struct WINE_GLXFBConfigSGIX* GLXFBConfigSGIX;
+#define GLX_WINDOW_BIT_SGIX 0x00000001
+#define GLX_PIXMAP_BIT_SGIX 0x00000002
+#define GLX_RGBA_BIT_SGIX 0x00000001
+#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002
+#define GLX_DRAWABLE_TYPE_SGIX 0x8010
+#define GLX_RENDER_TYPE_SGIX 0x8011
+#define GLX_X_RENDERABLE_SGIX 0x8012
+#define GLX_RGBA_TYPE_SGIX 0x8014
+#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015
+#endif
+typedef GLXFBConfigSGIX * (APIENTRY * PGLXFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements);
+typedef XVisualInfo * (APIENTRY * PGLXFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfig config);
+
+/* GLX_SGIX_pbuffer */
+#ifndef GLX_SGIX_pbuffer
+#define GLX_SGIX_pbuffer 1
+typedef struct WINE_GLXPbufferSGIX* GLXPbufferSGIX;
+#define GLX_PBUFFER_SGIX 0x8023
+#define GLX_PBUFFER_BIT_SGIX 0x00000004
+#endif
+typedef GLXPbufferSGIX (APIENTRY * PGLXFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int* attrib_list);
+typedef void (APIENTRY * PGLXFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer);
/****************************************************
* OpenGL GLX Official Version
@@ -1467,6 +1494,13 @@ typedef enum _GL_SupportedExt {
OPENGL_SUPPORTED_EXT_END
} GL_SupportedExt;
+/* GLX Supported Extensions */
+typedef enum _GLX_SupportedExt {
+ SGIX_FBCONFIG,
+ SGIX_PBUFFER,
+
+ GLX_SUPPORTED_EXT_END
+} GLX_SupportedExt;
/****************************************************
* #Defines
@@ -1715,6 +1749,12 @@ #define GL2_FUNCS_GEN \
USE_GL_FUNC(PGLFNVERTEXATTRIBPOINTERPROC, glVertexAttribPointer); \
#define GLX_EXT_FUNCS_GEN \
+ /** GLX_SGIX_fbconfig **/ \
+ USE_GL_FUNC(PGLXFNGLXCHOOSEFBCONFIGSGIXPROC, glXChooseFBConfigSGIX); \
+ USE_GL_FUNC(PGLXFNGLXGETVISUALFROMFBCONFIGSGIXPROC, glXGetVisualFromFBConfigSGIX); \
+ /** GLX_SGIX_pbuffer **/ \
+ USE_GL_FUNC(PGLXFNGLXCREATEGLXPBUFFERSGIXPROC, glXCreateGLXPbufferSGIX); \
+ USE_GL_FUNC(PGLXFNGLXDESTROYGLXPBUFFERSGIXPROC, glXDestroyGLXPbufferSGIX); \
/** GLX_VERSION_1_3 **/ \
USE_GL_FUNC(PGLXFNGLXCREATEPBUFFERPROC, glXCreatePbuffer); \
USE_GL_FUNC(PGLXFNGLXDESTROYPBUFFERPROC, glXDestroyPbuffer); \
@@ -1782,6 +1822,7 @@ typedef struct _WineD3D_GL_Info {
GL_VSVersion vs_ati_version;
BOOL supported[OPENGL_SUPPORTED_EXT_END + 1];
+ BOOL glx_supported[GLX_SUPPORTED_EXT_END + 1];
/** OpenGL EXT and ARB functions ptr */
GL_EXT_FUNCS_GEN;
--
1.4.1
More information about the wine-patches
mailing list