summaryrefslogtreecommitdiffstats
path: root/src/gallium/state_trackers/nine/swapchain9.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/state_trackers/nine/swapchain9.c')
-rw-r--r--src/gallium/state_trackers/nine/swapchain9.c871
1 files changed, 871 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c
new file mode 100644
index 00000000000..b6e81257aba
--- /dev/null
+++ b/src/gallium/state_trackers/nine/swapchain9.c
@@ -0,0 +1,871 @@
+/*
+ * Copyright 2011 Joakim Sindholt <[email protected]>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#include "swapchain9.h"
+#include "surface9.h"
+#include "device9.h"
+
+#include "nine_helpers.h"
+#include "nine_pipe.h"
+#include "nine_dump.h"
+
+#include "util/u_inlines.h"
+#include "util/u_surface.h"
+#include "hud/hud_context.h"
+#include "state_tracker/drm_driver.h"
+
+#define DBG_CHANNEL DBG_SWAPCHAIN
+
+#define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n)
+
+HRESULT
+NineSwapChain9_ctor( struct NineSwapChain9 *This,
+ struct NineUnknownParams *pParams,
+ BOOL implicit,
+ ID3DPresent *pPresent,
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
+ struct d3dadapter9_context *pCTX,
+ HWND hFocusWindow,
+ D3DDISPLAYMODEEX *mode )
+{
+ HRESULT hr;
+
+ DBG("This=%p pDevice=%p pPresent=%p pCTX=%p hFocusWindow=%p\n",
+ This, pParams->device, pPresent, pCTX, hFocusWindow);
+
+ hr = NineUnknown_ctor(&This->base, pParams);
+ if (FAILED(hr))
+ return hr;
+
+ This->screen = NineDevice9_GetScreen(This->base.device);
+ This->pipe = NineDevice9_GetPipe(This->base.device);
+ This->cso = NineDevice9_GetCSO(This->base.device);
+ This->implicit = implicit;
+ This->actx = pCTX;
+ This->present = pPresent;
+ This->mode = NULL;
+
+ ID3DPresent_AddRef(pPresent);
+
+ if (!pPresentationParameters->hDeviceWindow)
+ pPresentationParameters->hDeviceWindow = hFocusWindow;
+
+ This->rendering_done = FALSE;
+ return NineSwapChain9_Resize(This, pPresentationParameters, mode);
+}
+
+static D3DWindowBuffer *
+D3DWindowBuffer_create(struct NineSwapChain9 *This,
+ struct pipe_resource *resource,
+ int depth)
+{
+ D3DWindowBuffer *ret;
+ struct winsys_handle whandle;
+ int stride, dmaBufFd;
+
+ memset(&whandle, 0, sizeof(whandle));
+ whandle.type = DRM_API_HANDLE_TYPE_FD;
+ This->screen->resource_get_handle(This->screen, resource, &whandle);
+ stride = whandle.stride;
+ dmaBufFd = whandle.handle;
+ ID3DPresent_NewD3DWindowBufferFromDmaBuf(This->present,
+ dmaBufFd,
+ resource->width0,
+ resource->height0,
+ stride,
+ depth,
+ 32,
+ &ret);
+ return ret;
+}
+
+HRESULT
+NineSwapChain9_Resize( struct NineSwapChain9 *This,
+ D3DPRESENT_PARAMETERS *pParams,
+ D3DDISPLAYMODEEX *mode )
+{
+ struct NineDevice9 *pDevice = This->base.device;
+ struct NineSurface9 **bufs;
+ D3DSURFACE_DESC desc;
+ HRESULT hr;
+ struct pipe_resource *resource, tmplt;
+ enum pipe_format pf;
+ BOOL has_present_buffers = FALSE;
+ int depth;
+ unsigned i, oldBufferCount, newBufferCount;
+
+ DBG("This=%p pParams=%p\n", This, pParams);
+ user_assert(pParams != NULL, E_POINTER);
+
+ DBG("pParams(%p):\n"
+ "BackBufferWidth: %u\n"
+ "BackBufferHeight: %u\n"
+ "BackBufferFormat: %s\n"
+ "BackBufferCount: %u\n"
+ "MultiSampleType: %u\n"
+ "MultiSampleQuality: %u\n"
+ "SwapEffect: %u\n"
+ "hDeviceWindow: %p\n"
+ "Windowed: %i\n"
+ "EnableAutoDepthStencil: %i\n"
+ "AutoDepthStencilFormat: %s\n"
+ "Flags: %s\n"
+ "FullScreen_RefreshRateInHz: %u\n"
+ "PresentationInterval: %x\n", pParams,
+ pParams->BackBufferWidth, pParams->BackBufferHeight,
+ d3dformat_to_string(pParams->BackBufferFormat),
+ pParams->BackBufferCount,
+ pParams->MultiSampleType, pParams->MultiSampleQuality,
+ pParams->SwapEffect, pParams->hDeviceWindow, pParams->Windowed,
+ pParams->EnableAutoDepthStencil,
+ d3dformat_to_string(pParams->AutoDepthStencilFormat),
+ nine_D3DPRESENTFLAG_to_str(pParams->Flags),
+ pParams->FullScreen_RefreshRateInHz,
+ pParams->PresentationInterval);
+
+ if (pParams->SwapEffect == D3DSWAPEFFECT_COPY &&
+ pParams->BackBufferCount > 1) {
+ pParams->BackBufferCount = 1;
+ }
+
+ if (pParams->BackBufferCount > 3) {
+ pParams->BackBufferCount = 3;
+ }
+
+ if (pParams->BackBufferCount == 0) {
+ pParams->BackBufferCount = 1;
+ }
+
+ if (pParams->BackBufferFormat == D3DFMT_UNKNOWN) {
+ pParams->BackBufferFormat = D3DFMT_A8R8G8B8;
+ }
+
+ This->desired_fences = This->actx->throttling ? This->actx->throttling_value + 1 : 0;
+ /* +1 because we add the fence of the current buffer before popping an old one */
+ if (This->desired_fences > DRI_SWAP_FENCES_MAX)
+ This->desired_fences = DRI_SWAP_FENCES_MAX;
+
+ if (mode && This->mode) {
+ *(This->mode) = *mode;
+ } else if (mode) {
+ This->mode = malloc(sizeof(D3DDISPLAYMODEEX));
+ memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX));
+ } else if (This->mode) {
+ free(This->mode);
+ This->mode = NULL;
+ }
+
+ /* Note: It is the role of the backend to fill if neccessary
+ * BackBufferWidth and BackBufferHeight */
+ ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
+
+ /* When we have flip behaviour, d3d9 expects we get back the screen buffer when we flip.
+ * Here we don't get back the initial content of the screen. To emulate the behaviour
+ * we allocate an additional buffer */
+ oldBufferCount = This->params.BackBufferCount ?
+ (This->params.BackBufferCount +
+ (This->params.SwapEffect != D3DSWAPEFFECT_COPY)) : 0;
+ newBufferCount = pParams->BackBufferCount +
+ (pParams->SwapEffect != D3DSWAPEFFECT_COPY);
+
+ pf = d3d9_to_pipe_format(pParams->BackBufferFormat);
+ if (This->actx->linear_framebuffer ||
+ (pf != PIPE_FORMAT_B8G8R8X8_UNORM &&
+ pf != PIPE_FORMAT_B8G8R8A8_UNORM) ||
+ pParams->SwapEffect != D3DSWAPEFFECT_DISCARD ||
+ pParams->MultiSampleType >= 2 ||
+ (This->actx->ref && This->actx->ref == This->screen))
+ has_present_buffers = TRUE;
+
+ /* Note: the buffer depth has to match the window depth.
+ * In practice, ARGB buffers can be used with windows
+ * of depth 24. Windows of depth 32 are extremely rare.
+ * So even if the buffer is ARGB, say it is depth 24.
+ * It is common practice, for example that's how
+ * glamor implements depth 24.
+ * TODO: handle windows with other depths. Not possible in the short term.
+ * For example 16 bits.*/
+ depth = 24;
+
+ tmplt.target = PIPE_TEXTURE_2D;
+ tmplt.width0 = pParams->BackBufferWidth;
+ tmplt.height0 = pParams->BackBufferHeight;
+ tmplt.depth0 = 1;
+ tmplt.last_level = 0;
+ tmplt.array_size = 1;
+ tmplt.usage = PIPE_USAGE_DEFAULT;
+ tmplt.flags = 0;
+
+ desc.Type = D3DRTYPE_SURFACE;
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.MultiSampleType = pParams->MultiSampleType;
+ desc.MultiSampleQuality = 0;
+ desc.Width = pParams->BackBufferWidth;
+ desc.Height = pParams->BackBufferHeight;
+
+ for (i = 0; i < oldBufferCount; i++) {
+ ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
+ This->present_handles[i] = NULL;
+ if (This->present_buffers)
+ pipe_resource_reference(&(This->present_buffers[i]), NULL);
+ }
+
+ if (!has_present_buffers && This->present_buffers) {
+ FREE(This->present_buffers);
+ This->present_buffers = NULL;
+ }
+
+ if (newBufferCount != oldBufferCount) {
+ for (i = newBufferCount; i < oldBufferCount;
+ ++i)
+ NineUnknown_Detach(NineUnknown(This->buffers[i]));
+
+ bufs = REALLOC(This->buffers,
+ oldBufferCount * sizeof(This->buffers[0]),
+ newBufferCount * sizeof(This->buffers[0]));
+ if (!bufs)
+ return E_OUTOFMEMORY;
+ This->buffers = bufs;
+ if (has_present_buffers) {
+ This->present_buffers = REALLOC(This->present_buffers,
+ This->present_buffers == NULL ? 0 : oldBufferCount * sizeof(struct pipe_resource *),
+ newBufferCount * sizeof(struct pipe_resource *));
+ memset(This->present_buffers, 0, newBufferCount * sizeof(struct pipe_resource *));
+ }
+ This->present_handles = REALLOC(This->present_handles,
+ oldBufferCount * sizeof(D3DWindowBuffer *),
+ newBufferCount * sizeof(D3DWindowBuffer *));
+ for (i = oldBufferCount; i < newBufferCount; ++i) {
+ This->buffers[i] = NULL;
+ This->present_handles[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < newBufferCount; ++i) {
+ tmplt.format = d3d9_to_pipe_format(pParams->BackBufferFormat);
+ tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+ PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET;
+ tmplt.nr_samples = pParams->MultiSampleType;
+ if (!has_present_buffers)
+ tmplt.bind |= PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+ resource = This->screen->resource_create(This->screen, &tmplt);
+ if (!resource) {
+ DBG("Failed to create pipe_resource.\n");
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ if (pParams->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
+ resource->flags |= NINE_RESOURCE_FLAG_LOCKABLE;
+ if (This->buffers[i]) {
+ NineSurface9_SetResourceResize(This->buffers[i], resource);
+ if (has_present_buffers)
+ pipe_resource_reference(&resource, NULL);
+ } else {
+ desc.Format = pParams->BackBufferFormat;
+ desc.Usage = D3DUSAGE_RENDERTARGET;
+ hr = NineSurface9_new(pDevice, NineUnknown(This), resource, 0,
+ 0, 0, &desc, &This->buffers[i]);
+ if (has_present_buffers)
+ pipe_resource_reference(&resource, NULL);
+ if (FAILED(hr)) {
+ DBG("Failed to create RT surface.\n");
+ return hr;
+ }
+ This->buffers[i]->base.base.forward = FALSE;
+ }
+ if (has_present_buffers) {
+ tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+ tmplt.nr_samples = 0;
+ if (This->actx->linear_framebuffer)
+ tmplt.bind |= PIPE_BIND_LINEAR;
+ if (pParams->SwapEffect != D3DSWAPEFFECT_DISCARD)
+ tmplt.bind |= PIPE_BIND_RENDER_TARGET;
+ resource = This->screen->resource_create(This->screen, &tmplt);
+ pipe_resource_reference(&(This->present_buffers[i]), resource);
+ }
+ This->present_handles[i] = D3DWindowBuffer_create(This, resource, depth);
+ if (!has_present_buffers)
+ pipe_resource_reference(&resource, NULL);
+ }
+ if (pParams->EnableAutoDepthStencil) {
+ tmplt.format = d3d9_to_pipe_format(pParams->AutoDepthStencilFormat);
+ tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+ PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_DEPTH_STENCIL;
+ tmplt.nr_samples = pParams->MultiSampleType;
+
+ resource = This->screen->resource_create(This->screen, &tmplt);
+ if (!resource) {
+ DBG("Failed to create pipe_resource for depth buffer.\n");
+ return D3DERR_OUTOFVIDEOMEMORY;
+ }
+ if (This->zsbuf) {
+ NineSurface9_SetResourceResize(This->zsbuf, resource);
+ pipe_resource_reference(&resource, NULL);
+ } else {
+ /* XXX wine thinks the container of this should be the device */
+ desc.Format = pParams->AutoDepthStencilFormat;
+ desc.Usage = D3DUSAGE_DEPTHSTENCIL;
+ hr = NineSurface9_new(pDevice, NineUnknown(pDevice), resource, 0,
+ 0, 0, &desc, &This->zsbuf);
+ pipe_resource_reference(&resource, NULL);
+ if (FAILED(hr)) {
+ DBG("Failed to create ZS surface.\n");
+ return hr;
+ }
+ This->zsbuf->base.base.forward = FALSE;
+ }
+ }
+
+ This->params = *pParams;
+
+ return D3D_OK;
+}
+
+/* Throttling: code adapted from the dri state tracker */
+
+/**
+ * swap_fences_pop_front - pull a fence from the throttle queue
+ *
+ * If the throttle queue is filled to the desired number of fences,
+ * pull fences off the queue until the number is less than the desired
+ * number of fences, and return the last fence pulled.
+ */
+static struct pipe_fence_handle *
+swap_fences_pop_front(struct NineSwapChain9 *This)
+{
+ struct pipe_screen *screen = This->screen;
+ struct pipe_fence_handle *fence = NULL;
+
+ if (This->desired_fences == 0)
+ return NULL;
+
+ if (This->cur_fences >= This->desired_fences) {
+ screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
+ screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
+ This->tail &= DRI_SWAP_FENCES_MASK;
+ --This->cur_fences;
+ }
+ return fence;
+}
+
+
+/**
+ * swap_fences_see_front - same than swap_fences_pop_front without
+ * pulling
+ *
+ */
+
+static struct pipe_fence_handle *
+swap_fences_see_front(struct NineSwapChain9 *This)
+{
+ struct pipe_screen *screen = This->screen;
+ struct pipe_fence_handle *fence = NULL;
+
+ if (This->desired_fences == 0)
+ return NULL;
+
+ if (This->cur_fences >= This->desired_fences) {
+ screen->fence_reference(screen, &fence, This->swap_fences[This->tail]);
+ }
+ return fence;
+}
+
+
+/**
+ * swap_fences_push_back - push a fence onto the throttle queue at the back
+ *
+ * push a fence onto the throttle queue and pull fences of the queue
+ * so that the desired number of fences are on the queue.
+ */
+static void
+swap_fences_push_back(struct NineSwapChain9 *This,
+ struct pipe_fence_handle *fence)
+{
+ struct pipe_screen *screen = This->screen;
+
+ if (!fence || This->desired_fences == 0)
+ return;
+
+ while(This->cur_fences == This->desired_fences)
+ swap_fences_pop_front(This);
+
+ This->cur_fences++;
+ screen->fence_reference(screen, &This->swap_fences[This->head++],
+ fence);
+ This->head &= DRI_SWAP_FENCES_MASK;
+}
+
+
+/**
+ * swap_fences_unref - empty the throttle queue
+ *
+ * pulls fences of the throttle queue until it is empty.
+ */
+static void
+swap_fences_unref(struct NineSwapChain9 *This)
+{
+ struct pipe_screen *screen = This->screen;
+
+ while(This->cur_fences) {
+ screen->fence_reference(screen, &This->swap_fences[This->tail++], NULL);
+ This->tail &= DRI_SWAP_FENCES_MASK;
+ --This->cur_fences;
+ }
+}
+
+void
+NineSwapChain9_dtor( struct NineSwapChain9 *This )
+{
+ unsigned i;
+
+ DBG("This=%p\n", This);
+
+ if (This->buffers) {
+ for (i = 0; i < This->params.BackBufferCount; i++) {
+ NineUnknown_Destroy(NineUnknown(This->buffers[i]));
+ ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]);
+ if (This->present_buffers)
+ pipe_resource_reference(&(This->present_buffers[i]), NULL);
+ }
+ FREE(This->buffers);
+ FREE(This->present_buffers);
+ }
+ if (This->zsbuf)
+ NineUnknown_Destroy(NineUnknown(This->zsbuf));
+
+ if (This->present)
+ ID3DPresent_Release(This->present);
+
+ swap_fences_unref(This);
+ NineUnknown_dtor(&This->base);
+}
+
+static void
+create_present_buffer( struct NineSwapChain9 *This,
+ unsigned int width, unsigned int height,
+ struct pipe_resource **resource,
+ D3DWindowBuffer **present_handle)
+{
+ struct pipe_resource tmplt;
+
+ tmplt.target = PIPE_TEXTURE_2D;
+ tmplt.width0 = width;
+ tmplt.height0 = height;
+ tmplt.depth0 = 1;
+ tmplt.last_level = 0;
+ tmplt.array_size = 1;
+ tmplt.usage = PIPE_USAGE_DEFAULT;
+ tmplt.flags = 0;
+ tmplt.format = PIPE_FORMAT_B8G8R8X8_UNORM;
+ tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
+ PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET |
+ PIPE_BIND_SHARED | PIPE_BIND_SCANOUT | PIPE_BIND_DISPLAY_TARGET;
+ tmplt.nr_samples = 0;
+ if (This->actx->linear_framebuffer)
+ tmplt.bind |= PIPE_BIND_LINEAR;
+ *resource = This->screen->resource_create(This->screen, &tmplt);
+
+ *present_handle = D3DWindowBuffer_create(This, *resource, 24);
+}
+
+static void
+handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *resource)
+{
+ struct NineDevice9 *device = This->base.device;
+ struct pipe_blit_info blit;
+
+ if (device->cursor.software && device->cursor.visible && device->cursor.w) {
+ blit.src.resource = device->cursor.image;
+ blit.src.level = 0;
+ blit.src.format = device->cursor.image->format;
+ blit.src.box.x = 0;
+ blit.src.box.y = 0;
+ blit.src.box.z = 0;
+ blit.src.box.depth = 1;
+ blit.src.box.width = device->cursor.w;
+ blit.src.box.height = device->cursor.h;
+
+ blit.dst.resource = resource;
+ blit.dst.level = 0;
+ blit.dst.format = resource->format;
+ blit.dst.box.z = 0;
+ blit.dst.box.depth = 1;
+
+ blit.mask = PIPE_MASK_RGBA;
+ blit.filter = PIPE_TEX_FILTER_NEAREST;
+ blit.scissor_enable = FALSE;
+
+ ID3DPresent_GetCursorPos(This->present, &device->cursor.pos);
+
+ /* NOTE: blit messes up when box.x + box.width < 0, fix driver */
+ blit.dst.box.x = MAX2(device->cursor.pos.x, 0) - device->cursor.hotspot.x;
+ blit.dst.box.y = MAX2(device->cursor.pos.y, 0) - device->cursor.hotspot.y;
+ blit.dst.box.width = blit.src.box.width;
+ blit.dst.box.height = blit.src.box.height;
+
+ DBG("Blitting cursor(%ux%u) to (%i,%i).\n",
+ blit.src.box.width, blit.src.box.height,
+ blit.dst.box.x, blit.dst.box.y);
+
+ This->pipe->blit(This->pipe, &blit);
+ }
+
+ if (device->hud && resource) {
+ hud_draw(device->hud, resource); /* XXX: no offset */
+ /* HUD doesn't clobber stipple */
+ NineDevice9_RestoreNonCSOState(device, ~0x2);
+ }
+}
+
+static INLINE HRESULT
+present( struct NineSwapChain9 *This,
+ const RECT *pSourceRect,
+ const RECT *pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA *pDirtyRegion,
+ DWORD dwFlags )
+{
+ struct pipe_resource *resource;
+ struct pipe_fence_handle *fence;
+ HRESULT hr;
+ struct pipe_blit_info blit;
+
+ DBG("present: This=%p pSourceRect=%p pDestRect=%p "
+ "pDirtyRegion=%p hDestWindowOverride=%p"
+ "dwFlags=%d resource=%p\n",
+ This, pSourceRect, pDestRect, pDirtyRegion,
+ hDestWindowOverride, (int)dwFlags, This->buffers[0]->base.resource);
+
+ if (pSourceRect)
+ DBG("pSourceRect = (%u..%u)x(%u..%u)\n",
+ pSourceRect->left, pSourceRect->right,
+ pSourceRect->top, pSourceRect->bottom);
+ if (pDestRect)
+ DBG("pDestRect = (%u..%u)x(%u..%u)\n",
+ pDestRect->left, pDestRect->right,
+ pDestRect->top, pDestRect->bottom);
+
+ /* TODO: in the case the source and destination rect have different size:
+ * We need to allocate a new buffer, and do a blit to it to resize.
+ * We can't use the present_buffer for that since when we created it,
+ * we couldn't guess which size would have been needed.
+ * If pDestRect or pSourceRect is null, we have to check the sizes
+ * from the source size, and the destination window size.
+ * In this case, either resize rngdata, or pass NULL instead
+ */
+ /* Note: This->buffers[0]->level should always be 0 */
+
+ if (This->rendering_done)
+ goto bypass_rendering;
+
+ resource = This->buffers[0]->base.resource;
+
+ if (This->params.SwapEffect == D3DSWAPEFFECT_DISCARD)
+ handle_draw_cursor_and_hud(This, resource);
+
+ if (This->present_buffers) {
+ blit.src.resource = resource;
+ blit.src.level = 0;
+ blit.src.format = resource->format;
+ blit.src.box.z = 0;
+ blit.src.box.depth = 1;
+ blit.src.box.x = 0;
+ blit.src.box.y = 0;
+ blit.src.box.width = resource->width0;
+ blit.src.box.height = resource->height0;
+
+ resource = This->present_buffers[0];
+
+ blit.dst.resource = resource;
+ blit.dst.level = 0;
+ blit.dst.format = resource->format;
+ blit.dst.box.z = 0;
+ blit.dst.box.depth = 1;
+ blit.dst.box.x = 0;
+ blit.dst.box.y = 0;
+ blit.dst.box.width = resource->width0;
+ blit.dst.box.height = resource->height0;
+
+ blit.mask = PIPE_MASK_RGBA;
+ blit.filter = PIPE_TEX_FILTER_NEAREST;
+ blit.scissor_enable = FALSE;
+
+ This->pipe->blit(This->pipe, &blit);
+ }
+
+ if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
+ handle_draw_cursor_and_hud(This, resource);
+
+ fence = NULL;
+ This->pipe->flush(This->pipe, &fence, PIPE_FLUSH_END_OF_FRAME);
+ if (fence) {
+ swap_fences_push_back(This, fence);
+ This->screen->fence_reference(This->screen, &fence, NULL);
+ }
+
+ This->rendering_done = TRUE;
+bypass_rendering:
+
+ if (dwFlags & D3DPRESENT_DONOTWAIT) {
+ UNTESTED(2);
+ BOOL still_draw = FALSE;
+ fence = swap_fences_see_front(This);
+ if (fence) {
+ still_draw = !This->screen->fence_signalled(This->screen, fence);
+ This->screen->fence_reference(This->screen, &fence, NULL);
+ }
+ if (still_draw)
+ return D3DERR_WASSTILLDRAWING;
+ }
+
+ fence = swap_fences_pop_front(This);
+ if (fence) {
+ (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE);
+ This->screen->fence_reference(This->screen, &fence, NULL);
+ }
+
+ if (This->present_buffers)
+ resource = This->present_buffers[0];
+ else
+ resource = This->buffers[0]->base.resource;
+ This->pipe->flush_resource(This->pipe, resource);
+ hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags);
+
+ if (FAILED(hr)) { UNTESTED(3);return hr; }
+
+ This->rendering_done = FALSE;
+
+ return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_Present( struct NineSwapChain9 *This,
+ const RECT *pSourceRect,
+ const RECT *pDestRect,
+ HWND hDestWindowOverride,
+ const RGNDATA *pDirtyRegion,
+ DWORD dwFlags )
+{
+ struct pipe_resource *res = NULL;
+ D3DWindowBuffer *handle_temp;
+ int i;
+ BOOL released;
+ HRESULT hr = present(This, pSourceRect, pDestRect,
+ hDestWindowOverride, pDirtyRegion, dwFlags);
+
+ if (hr == D3DERR_WASSTILLDRAWING)
+ return hr;
+
+ switch (This->params.SwapEffect) {
+ case D3DSWAPEFFECT_FLIP:
+ UNTESTED(4);
+ case D3DSWAPEFFECT_DISCARD:
+ /* rotate the queue */;
+ pipe_resource_reference(&res, This->buffers[0]->base.resource);
+ for (i = 1; i <= This->params.BackBufferCount; i++) {
+ NineSurface9_SetResourceResize(This->buffers[i - 1],
+ This->buffers[i]->base.resource);
+ }
+ NineSurface9_SetResourceResize(
+ This->buffers[This->params.BackBufferCount], res);
+ pipe_resource_reference(&res, NULL);
+
+ if (This->present_buffers) {
+ pipe_resource_reference(&res, This->present_buffers[0]);
+ for (i = 1; i <= This->params.BackBufferCount; i++)
+ pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]);
+ pipe_resource_reference(&(This->present_buffers[This->params.BackBufferCount]), res);
+ pipe_resource_reference(&res, NULL);
+ }
+
+ handle_temp = This->present_handles[0];
+ for (i = 1; i <= This->params.BackBufferCount; i++) {
+ This->present_handles[i-1] = This->present_handles[i];
+ }
+ This->present_handles[This->params.BackBufferCount] = handle_temp;
+ break;
+
+ case D3DSWAPEFFECT_COPY:
+ UNTESTED(5);
+ /* do nothing */
+ break;
+
+ case D3DSWAPEFFECT_OVERLAY:
+ /* XXX not implemented */
+ break;
+
+ case D3DSWAPEFFECT_FLIPEX:
+ /* XXX not implemented */
+ break;
+ }
+
+ ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]);
+
+ This->base.device->state.changed.group |= NINE_STATE_FB;
+ nine_update_state(This->base.device, NINE_STATE_FB);
+
+ return hr;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
+ IDirect3DSurface9 *pDestSurface )
+{
+ struct NineSurface9 *dest_surface = NineSurface9(pDestSurface);
+ struct NineDevice9 *pDevice = This->base.device;
+ unsigned int width, height;
+ struct pipe_resource *temp_resource;
+ struct NineSurface9 *temp_surface;
+ D3DWindowBuffer *temp_handle;
+ D3DSURFACE_DESC desc;
+ HRESULT hr;
+
+ DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
+ This, pDestSurface);
+
+ width = dest_surface->desc.Width;
+ height = dest_surface->desc.Height;
+
+ /* Note: front window size and destination size are supposed
+ * to match. However it's not very clear what should get taken in Windowed
+ * mode. It may need a fix */
+ create_present_buffer(This, width, height, &temp_resource, &temp_handle);
+
+ desc.Type = D3DRTYPE_SURFACE;
+ desc.Pool = D3DPOOL_DEFAULT;
+ desc.MultiSampleType = D3DMULTISAMPLE_NONE;
+ desc.MultiSampleQuality = 0;
+ desc.Width = width;
+ desc.Height = height;
+ /* NineSurface9_CopySurface needs same format. */
+ desc.Format = dest_surface->desc.Format;
+ desc.Usage = D3DUSAGE_RENDERTARGET;
+ hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, 0,
+ 0, 0, &desc, &temp_surface);
+ pipe_resource_reference(&temp_resource, NULL);
+ if (FAILED(hr)) {
+ DBG("Failed to create temp FrontBuffer surface.\n");
+ return hr;
+ }
+
+ ID3DPresent_FrontBufferCopy(This->present, temp_handle);
+
+ NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL);
+
+ ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
+ NineUnknown_Destroy(NineUnknown(temp_surface));
+
+ return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
+ UINT iBackBuffer,
+ D3DBACKBUFFER_TYPE Type,
+ IDirect3DSurface9 **ppBackBuffer )
+{
+ DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
+ This, iBackBuffer, Type, ppBackBuffer);
+ (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
+ user_assert(iBackBuffer < This->params.BackBufferCount, D3DERR_INVALIDCALL);
+ user_assert(ppBackBuffer != NULL, E_POINTER);
+
+ NineUnknown_AddRef(NineUnknown(This->buffers[iBackBuffer]));
+ *ppBackBuffer = (IDirect3DSurface9 *)This->buffers[iBackBuffer];
+ return D3D_OK;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetRasterStatus( struct NineSwapChain9 *This,
+ D3DRASTER_STATUS *pRasterStatus )
+{
+ DBG("GetRasterStatus: This=%p pRasterStatus=%p\n",
+ This, pRasterStatus);
+ user_assert(pRasterStatus != NULL, E_POINTER);
+ return ID3DPresent_GetRasterStatus(This->present, pRasterStatus);
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetDisplayMode( struct NineSwapChain9 *This,
+ D3DDISPLAYMODE *pMode )
+{
+ D3DDISPLAYMODEEX mode;
+ D3DDISPLAYROTATION rot;
+ HRESULT hr;
+
+ DBG("GetDisplayMode: This=%p pMode=%p\n",
+ This, pMode);
+ user_assert(pMode != NULL, E_POINTER);
+
+ hr = ID3DPresent_GetDisplayMode(This->present, &mode, &rot);
+ if (SUCCEEDED(hr)) {
+ pMode->Width = mode.Width;
+ pMode->Height = mode.Height;
+ pMode->RefreshRate = mode.RefreshRate;
+ pMode->Format = mode.Format;
+ }
+ return hr;
+}
+
+HRESULT WINAPI
+NineSwapChain9_GetPresentParameters( struct NineSwapChain9 *This,
+ D3DPRESENT_PARAMETERS *pPresentationParameters )
+{
+ DBG("GetPresentParameters: This=%p pPresentationParameters=%p\n",
+ This, pPresentationParameters);
+ user_assert(pPresentationParameters != NULL, E_POINTER);
+ *pPresentationParameters = This->params;
+ return D3D_OK;
+}
+
+IDirect3DSwapChain9Vtbl NineSwapChain9_vtable = {
+ (void *)NineUnknown_QueryInterface,
+ (void *)NineUnknown_AddRef,
+ (void *)NineUnknown_Release,
+ (void *)NineSwapChain9_Present,
+ (void *)NineSwapChain9_GetFrontBufferData,
+ (void *)NineSwapChain9_GetBackBuffer,
+ (void *)NineSwapChain9_GetRasterStatus,
+ (void *)NineSwapChain9_GetDisplayMode,
+ (void *)NineUnknown_GetDevice, /* actually part of SwapChain9 iface */
+ (void *)NineSwapChain9_GetPresentParameters
+};
+
+static const GUID *NineSwapChain9_IIDs[] = {
+ &IID_IDirect3DSwapChain9,
+ &IID_IUnknown,
+ NULL
+};
+
+HRESULT
+NineSwapChain9_new( struct NineDevice9 *pDevice,
+ BOOL implicit,
+ ID3DPresent *pPresent,
+ D3DPRESENT_PARAMETERS *pPresentationParameters,
+ struct d3dadapter9_context *pCTX,
+ HWND hFocusWindow,
+ struct NineSwapChain9 **ppOut )
+{
+ NINE_DEVICE_CHILD_NEW(SwapChain9, ppOut, pDevice, /* args */
+ implicit, pPresent, pPresentationParameters,
+ pCTX, hFocusWindow, NULL);
+}