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; int i; HRESULT hr = present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); switch (This->params.SwapEffect) { case D3DSWAPEFFECT_DISCARD: /* rotate the queue */ if (This->params.BackBufferCount == 1) break; 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 - 1], res); pipe_resource_reference(&res, NULL); break; case D3DSWAPEFFECT_FLIP: /* XXX not implemented */ break; case D3DSWAPEFFECT_COPY: /* do nothing */ break; case D3DSWAPEFFECT_OVERLAY: /* XXX not implemented */ break; case D3DSWAPEFFECT_FLIPEX: /* XXX not implemented */ break; } This->base.device->state.changed.group |= NINE_STATE_FB; nine_update_state(This->base.device, NINE_STATE_FB); return hr; }
HRESULT NINE_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; struct threadpool_task *task_temp; int i; HRESULT hr; DBG("This=%p pSourceRect=%p pDestRect=%p hDestWindowOverride=%p " "pDirtyRegion=%p dwFlags=%d\n", This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion,dwFlags); if (This->base.device->ex) { if (NineSwapChain9_GetOccluded(This)) { DBG("Present is occluded. Returning S_PRESENT_OCCLUDED.\n"); return S_PRESENT_OCCLUDED; } } else { if (NineSwapChain9_GetOccluded(This) || NineSwapChain9_ResolutionMismatch(This)) { This->base.device->device_needs_reset = TRUE; } if (This->base.device->device_needs_reset) { DBG("Device is lost. Returning D3DERR_DEVICELOST.\n"); return D3DERR_DEVICELOST; } } nine_csmt_process(This->base.device); hr = present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); if (hr == D3DERR_WASSTILLDRAWING) return hr; if (This->base.device->minor_version_num > 2 && This->params.SwapEffect == D3DSWAPEFFECT_DISCARD && This->params.PresentationInterval == D3DPRESENT_INTERVAL_IMMEDIATE && !This->actx->thread_submit) { int next_buffer = -1; while (next_buffer == -1) { /* Find a free backbuffer */ for (i = 1; i < This->num_back_buffers; i++) { if (ID3DPresent_IsBufferReleased(This->present, This->present_handles[i])) { DBG("Found buffer released: %d\n", i); next_buffer = i; break; } } if (next_buffer == -1) { DBG("Found no buffer released. Waiting for event\n"); ID3DPresent_WaitBufferReleaseEvent(This->present); } } /* Switch with the released buffer */ pipe_resource_reference(&res, This->buffers[0]->base.resource); NineSurface9_SetResourceResize( This->buffers[0], This->buffers[next_buffer]->base.resource); NineSurface9_SetResourceResize( This->buffers[next_buffer], res); pipe_resource_reference(&res, NULL); if (This->present_buffers[0]) { pipe_resource_reference(&res, This->present_buffers[0]); pipe_resource_reference(&This->present_buffers[0], This->present_buffers[next_buffer]); pipe_resource_reference(&This->present_buffers[next_buffer], res); pipe_resource_reference(&res, NULL); } handle_temp = This->present_handles[0]; This->present_handles[0] = This->present_handles[next_buffer]; This->present_handles[next_buffer] = handle_temp; /* Path not yet compatible with thread_submit */ assert(!This->tasks[0] && !This->tasks[next_buffer]); } else { switch (This->params.SwapEffect) { case D3DSWAPEFFECT_OVERLAY: /* Not implemented, fallback to FLIP */ case D3DSWAPEFFECT_FLIPEX: /* Allows optimizations over FLIP for windowed mode. */ case D3DSWAPEFFECT_DISCARD: /* Allows optimizations over FLIP */ case D3DSWAPEFFECT_FLIP: /* rotate the queue */ pipe_resource_reference(&res, This->buffers[0]->base.resource); for (i = 1; i < This->num_back_buffers; i++) { NineSurface9_SetResourceResize(This->buffers[i - 1], This->buffers[i]->base.resource); } NineSurface9_SetResourceResize( This->buffers[This->num_back_buffers - 1], res); pipe_resource_reference(&res, NULL); if (This->present_buffers[0]) { pipe_resource_reference(&res, This->present_buffers[0]); for (i = 1; i < This->num_back_buffers; i++) pipe_resource_reference(&(This->present_buffers[i-1]), This->present_buffers[i]); pipe_resource_reference(&(This->present_buffers[This->num_back_buffers - 1]), res); pipe_resource_reference(&res, NULL); } handle_temp = This->present_handles[0]; for (i = 1; i < This->num_back_buffers; i++) { This->present_handles[i-1] = This->present_handles[i]; } This->present_handles[This->num_back_buffers - 1] = handle_temp; task_temp = This->tasks[0]; for (i = 1; i < This->num_back_buffers; i++) { This->tasks[i-1] = This->tasks[i]; } This->tasks[This->num_back_buffers - 1] = task_temp; break; case D3DSWAPEFFECT_COPY: /* do nothing */ break; } if (This->tasks[0]) _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); } This->base.device->context.changed.group |= NINE_STATE_FB; return hr; }
HRESULT NineSwapChain9_Resize( struct NineSwapChain9 *This, D3DPRESENT_PARAMETERS *pParams, D3DDISPLAYMODEEX *mode ) { struct NineDevice9 *pDevice = This->base.device; 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; D3DMULTISAMPLE_TYPE multisample_type; DBG("This=%p pParams=%p\n", This, pParams); user_assert(pParams != NULL, E_POINTER); user_assert(pParams->SwapEffect, D3DERR_INVALIDCALL); user_assert((pParams->SwapEffect != D3DSWAPEFFECT_COPY) || (pParams->BackBufferCount <= 1), D3DERR_INVALIDCALL); user_assert(pDevice->ex || pParams->BackBufferCount <= D3DPRESENT_BACK_BUFFERS_MAX, D3DERR_INVALIDCALL); user_assert(!pDevice->ex || pParams->BackBufferCount <= D3DPRESENT_BACK_BUFFERS_MAX_EX, D3DERR_INVALIDCALL); user_assert(pDevice->ex || (pParams->SwapEffect == D3DSWAPEFFECT_FLIP) || (pParams->SwapEffect == D3DSWAPEFFECT_COPY) || (pParams->SwapEffect == D3DSWAPEFFECT_DISCARD), D3DERR_INVALIDCALL); 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->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 (This->actx->vblank_mode == 0) pParams->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; else if (This->actx->vblank_mode == 3) pParams->PresentationInterval = D3DPRESENT_INTERVAL_ONE; if (mode && This->mode) { *(This->mode) = *mode; } else if (mode) { This->mode = malloc(sizeof(D3DDISPLAYMODEEX)); memcpy(This->mode, mode, sizeof(D3DDISPLAYMODEEX)); } else { free(This->mode); This->mode = NULL; } /* Note: It is the role of the backend to fill if necessary * BackBufferWidth and BackBufferHeight */ hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode); if (hr != D3D_OK) return hr; oldBufferCount = This->num_back_buffers; newBufferCount = NineSwapChain9_GetBackBufferCountForParams(This, pParams); multisample_type = pParams->MultiSampleType; /* Map MultiSampleQuality to MultiSampleType */ hr = d3dmultisample_type_check(This->screen, pParams->BackBufferFormat, &multisample_type, pParams->MultiSampleQuality, NULL); if (FAILED(hr)) { return hr; } pf = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat, PIPE_TEXTURE_2D, multisample_type, PIPE_BIND_RENDER_TARGET, FALSE, FALSE); if (This->actx->linear_framebuffer || (pf != PIPE_FORMAT_B8G8R8X8_UNORM && pf != PIPE_FORMAT_B8G8R8A8_UNORM) || pParams->SwapEffect != D3DSWAPEFFECT_DISCARD || multisample_type >= 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; memset(&tmplt, 0, sizeof(tmplt)); 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 = pParams->MultiSampleQuality; desc.Width = pParams->BackBufferWidth; desc.Height = pParams->BackBufferHeight; for (i = 0; i < oldBufferCount; i++) { if (This->tasks[i]) _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[i])); } memset(This->tasks, 0, sizeof(This->tasks)); if (This->pool) { _mesa_threadpool_destroy(This, This->pool); This->pool = NULL; } This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY); if (This->enable_threadpool) This->pool = _mesa_threadpool_create(This); if (!This->pool) This->enable_threadpool = FALSE; for (i = 0; i < oldBufferCount; i++) { ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); This->present_handles[i] = NULL; if (This->present_buffers[i]) pipe_resource_reference(&(This->present_buffers[i]), NULL); } if (newBufferCount != oldBufferCount) { for (i = newBufferCount; i < oldBufferCount; ++i) NineUnknown_Detach(NineUnknown(This->buffers[i])); for (i = oldBufferCount; i < newBufferCount; ++i) { This->buffers[i] = NULL; This->present_handles[i] = NULL; } } This->num_back_buffers = newBufferCount; for (i = 0; i < newBufferCount; ++i) { tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; tmplt.nr_samples = multisample_type; if (!has_present_buffers) tmplt.bind |= NINE_BIND_PRESENTBUFFER_FLAGS; tmplt.format = d3d9_to_pipe_format_checked(This->screen, pParams->BackBufferFormat, PIPE_TEXTURE_2D, tmplt.nr_samples, tmplt.bind, FALSE, FALSE); if (tmplt.format == PIPE_FORMAT_NONE) return D3DERR_INVALIDCALL; 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_SetMultiSampleType(This->buffers[i], desc.MultiSampleType); 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, NULL, 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 = NINE_BIND_PRESENTBUFFER_FLAGS; 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, false); pipe_resource_reference(&resource, NULL); if (!This->present_handles[i]) { return D3DERR_DRIVERINTERNALERROR; } } if (pParams->EnableAutoDepthStencil) { tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat); tmplt.nr_samples = multisample_type; tmplt.format = d3d9_to_pipe_format_checked(This->screen, pParams->AutoDepthStencilFormat, PIPE_TEXTURE_2D, tmplt.nr_samples, tmplt.bind, FALSE, FALSE); if (tmplt.format == PIPE_FORMAT_NONE) return D3DERR_INVALIDCALL; if (This->zsbuf) { resource = This->screen->resource_create(This->screen, &tmplt); if (!resource) { DBG("Failed to create pipe_resource for depth buffer.\n"); return D3DERR_OUTOFVIDEOMEMORY; } NineSurface9_SetMultiSampleType(This->zsbuf, desc.MultiSampleType); NineSurface9_SetResourceResize(This->zsbuf, resource); pipe_resource_reference(&resource, NULL); } else { hr = NineDevice9_CreateDepthStencilSurface(pDevice, pParams->BackBufferWidth, pParams->BackBufferHeight, pParams->AutoDepthStencilFormat, pParams->MultiSampleType, pParams->MultiSampleQuality, 0, (IDirect3DSurface9 **)&This->zsbuf, NULL); if (FAILED(hr)) { DBG("Failed to create ZS surface.\n"); return hr; } NineUnknown_ConvertRefToBind(NineUnknown(This->zsbuf)); } } This->params = *pParams; return D3D_OK; }
HRESULT NineSwapChain9_Resize( struct NineSwapChain9 *This, D3DPRESENT_PARAMETERS *pParams ) { struct NineDevice9 *pDevice = This->base.device; struct NineSurface9 **bufs; D3DSURFACE_DESC desc; HRESULT hr; struct pipe_resource *resource, tmplt; unsigned i; DBG("This=%p pParams=%p\n", This, pParams); if (pParams) { 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->BackBufferFormat == D3DFMT_UNKNOWN) pParams->BackBufferFormat = This->params.BackBufferFormat; if (pParams->EnableAutoDepthStencil && This->params.EnableAutoDepthStencil && pParams->AutoDepthStencilFormat == D3DFMT_UNKNOWN) pParams->AutoDepthStencilFormat = This->params.AutoDepthStencilFormat; /* NULL means focus window. if (!pParams->hDeviceWindow && This->params.hDeviceWindow) pParams->hDeviceWindow = This->params.hDeviceWindow; */ if (pParams->BackBufferCount == 0) pParams->BackBufferCount = 1; /* ref MSDN */ if (pParams->BackBufferWidth == 0 || pParams->BackBufferHeight == 0) { RECT rect; if (!pParams->Windowed) return D3DERR_INVALIDCALL; if (FAILED(ID3DPresent_GetWindowRect(This->present, NULL, &rect))) { rect.right = This->params.BackBufferWidth; rect.bottom = This->params.BackBufferHeight; } if (!pParams->BackBufferWidth) pParams->BackBufferWidth = rect.right; if (!pParams->BackBufferHeight) pParams->BackBufferHeight = rect.bottom; } tmplt.target = PIPE_TEXTURE_2D; tmplt.width0 = pParams->BackBufferWidth; tmplt.height0 = pParams->BackBufferHeight; tmplt.depth0 = 1; tmplt.nr_samples = pParams->MultiSampleType; tmplt.last_level = 0; tmplt.array_size = 1; tmplt.usage = PIPE_USAGE_DEFAULT; tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ | PIPE_BIND_TRANSFER_WRITE; 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; if (pParams->BackBufferCount != This->params.BackBufferCount) { for (i = pParams->BackBufferCount; i < This->params.BackBufferCount; ++i) NineUnknown_Detach(NineUnknown(This->buffers[i])); bufs = REALLOC(This->buffers, This->params.BackBufferCount * sizeof(This->buffers[0]), pParams->BackBufferCount * sizeof(This->buffers[0])); if (!bufs) return E_OUTOFMEMORY; This->buffers = bufs; for (i = This->params.BackBufferCount; i < pParams->BackBufferCount; ++i) This->buffers[i] = NULL; } for (i = 0; i < pParams->BackBufferCount; ++i) { tmplt.format = d3d9_to_pipe_format(pParams->BackBufferFormat); tmplt.bind |= PIPE_BIND_RENDER_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); 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]); 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 (pParams->EnableAutoDepthStencil) { tmplt.format = d3d9_to_pipe_format(pParams->AutoDepthStencilFormat); tmplt.bind &= ~PIPE_BIND_RENDER_TARGET; tmplt.bind |= PIPE_BIND_DEPTH_STENCIL; 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 the 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; }