st/nine: Handle Window Occlusion
[mesa.git] / src / gallium / state_trackers / nine / swapchain9.c
index de61dad8e09eec01da247be50a9cdf55b8016e83..5d05f1f46975c6236c7cd485da7f171a7cf78d62 100644 (file)
@@ -118,6 +118,14 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
 
     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 <= 3, 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"
@@ -145,11 +153,6 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
         pParams->FullScreen_RefreshRateInHz,
         pParams->PresentationInterval);
 
-    if (pParams->SwapEffect == D3DSWAPEFFECT_COPY &&
-        pParams->BackBufferCount > 1) {
-        pParams->BackBufferCount = 1;
-    }
-
     if (pParams->BackBufferCount > 3) {
         pParams->BackBufferCount = 3;
     }
@@ -182,9 +185,11 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
         This->mode = NULL;
     }
 
-    /* Note: It is the role of the backend to fill if neccessary
+    /* Note: It is the role of the backend to fill if necessary
      * BackBufferWidth and BackBufferHeight */
-    ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
+    hr = ID3DPresent_SetPresentParameters(This->present, pParams, This->mode);
+    if (hr != D3D_OK)
+        return hr;
 
     /* 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
@@ -271,12 +276,6 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
         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 *));
@@ -286,6 +285,15 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
         }
     }
 
+    if (has_present_buffers &&
+        (newBufferCount != oldBufferCount || !This->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 *));
+    }
+
     for (i = 0; i < newBufferCount; ++i) {
         tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
                      PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_RENDER_TARGET;
@@ -335,12 +343,17 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
             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);
+        pipe_resource_reference(&resource, NULL);
     }
     if (pParams->EnableAutoDepthStencil) {
-        tmplt.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_TRANSFER_READ |
-                     PIPE_BIND_TRANSFER_WRITE | PIPE_BIND_DEPTH_STENCIL;
+        tmplt.bind = d3d9_get_pipe_depth_format_bindings(pParams->AutoDepthStencilFormat);
+        /* Checking the d3d9 depth format for texture support indicates the app if it can use
+         * the format for shadow mapping or texturing. If the check returns true, then the app
+         * is allowed to use this functionnality, so try first to create the buffer
+         * with PIPE_BIND_SAMPLER_VIEW. If the format can't be created with it, try without.
+         * If it fails with PIPE_BIND_SAMPLER_VIEW, then the app check for texture support
+         * would fail too, so we are fine. */
+        tmplt.bind |= PIPE_BIND_SAMPLER_VIEW;
         tmplt.nr_samples = pParams->MultiSampleType;
         tmplt.format = d3d9_to_pipe_format_checked(This->screen,
                                                    pParams->AutoDepthStencilFormat,
@@ -348,6 +361,16 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This,
                                                    tmplt.nr_samples,
                                                    tmplt.bind,
                                                    FALSE);
+        if (tmplt.format == PIPE_FORMAT_NONE) {
+            tmplt.bind &= ~PIPE_BIND_SAMPLER_VIEW;
+            tmplt.format = d3d9_to_pipe_format_checked(This->screen,
+                                                       pParams->AutoDepthStencilFormat,
+                                                       PIPE_TEXTURE_2D,
+                                                       tmplt.nr_samples,
+                                                       tmplt.bind,
+                                                       FALSE);
+        }
+
         if (tmplt.format == PIPE_FORMAT_NONE)
             return D3DERR_INVALIDCALL;
 
@@ -536,6 +559,7 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r
     struct pipe_blit_info blit;
 
     if (device->cursor.software && device->cursor.visible && device->cursor.w) {
+        memset(&blit, 0, sizeof(blit));
         blit.src.resource = device->cursor.image;
         blit.src.level = 0;
         blit.src.format = device->cursor.image->format;
@@ -556,9 +580,10 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r
         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 */
+        /* NOTE: blit messes up when box.x + box.width < 0, fix driver
+         * NOTE2: device->cursor.pos contains coordinates relative to the screen.
+         * This happens to be also the position of the cursor when we are fullscreen.
+         * We don't use sw cursor for Windowed mode */
         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;
@@ -568,13 +593,14 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r
             blit.src.box.width, blit.src.box.height,
             blit.dst.box.x, blit.dst.box.y);
 
+        blit.alpha_blend = TRUE;
         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);
+        nine_state_restore_non_cso(device);
     }
 }
 
@@ -612,7 +638,7 @@ static void pend_present(struct NineSwapChain9 *This,
     return;
 }
 
-static INLINE HRESULT
+static inline HRESULT
 present( struct NineSwapChain9 *This,
          const RECT *pSourceRect,
          const RECT *pDestRect,
@@ -659,6 +685,7 @@ present( struct NineSwapChain9 *This,
         handle_draw_cursor_and_hud(This, resource);
 
     if (This->present_buffers) {
+        memset(&blit, 0, sizeof(blit));
         blit.src.resource = resource;
         blit.src.level = 0;
         blit.src.format = resource->format;
@@ -684,10 +711,15 @@ present( struct NineSwapChain9 *This,
         blit.mask = PIPE_MASK_RGBA;
         blit.filter = PIPE_TEX_FILTER_NEAREST;
         blit.scissor_enable = FALSE;
+        blit.alpha_blend = FALSE;
 
         This->pipe->blit(This->pipe, &blit);
     }
 
+    /* The resource we present has to resolve fast clears
+     * if needed (and other things) */
+    This->pipe->flush_resource(This->pipe, resource);
+
     if (This->params.SwapEffect != D3DSWAPEFFECT_DISCARD)
         handle_draw_cursor_and_hud(This, resource);
 
@@ -706,19 +738,13 @@ bypass_rendering:
         BOOL still_draw = FALSE;
         fence = swap_fences_see_front(This);
         if (fence) {
-            still_draw = !This->screen->fence_signalled(This->screen, fence);
+            still_draw = !This->screen->fence_finish(This->screen, fence, 0);
             This->screen->fence_reference(This->screen, &fence, NULL);
         }
         if (still_draw)
             return D3DERR_WASSTILLDRAWING;
     }
 
-    if (This->present_buffers)
-        resource = This->present_buffers[0];
-    else
-        resource = This->buffers[0]->base.resource;
-    This->pipe->flush_resource(This->pipe, resource);
-
     if (!This->enable_threadpool) {
         This->tasks[0]=NULL;
         fence = swap_fences_pop_front(This);
@@ -761,11 +787,24 @@ NineSwapChain9_Present( struct NineSwapChain9 *This,
     if (hr == D3DERR_WASSTILLDRAWING)
         return hr;
 
+    if (This->base.device->ex) {
+        if (NineSwapChain9_GetOccluded(This)) {
+            return S_PRESENT_OCCLUDED;
+        }
+    } else {
+        if (NineSwapChain9_GetOccluded(This)) {
+            This->base.device->device_needs_reset = TRUE;
+        }
+        if (This->base.device->device_needs_reset) {
+            return D3DERR_DEVICELOST;
+        }
+    }
+
     switch (This->params.SwapEffect) {
         case D3DSWAPEFFECT_FLIP:
             UNTESTED(4);
         case D3DSWAPEFFECT_DISCARD:
-            /* rotate the queue */;
+            /* 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],
@@ -815,7 +854,7 @@ NineSwapChain9_Present( struct NineSwapChain9 *This,
     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);
+    nine_update_state_framebuffer(This->base.device);
 
     return hr;
 }
@@ -836,6 +875,8 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
     DBG("GetFrontBufferData: This=%p pDestSurface=%p\n",
         This, pDestSurface);
 
+    user_assert(dest_surface->base.pool == D3DPOOL_SYSTEMMEM, D3DERR_INVALIDCALL);
+
     width = dest_surface->desc.Width;
     height = dest_surface->desc.Height;
 
@@ -850,7 +891,7 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
     desc.MultiSampleQuality = 0;
     desc.Width = width;
     desc.Height = height;
-    /* NineSurface9_CopySurface needs same format. */
+    /* NineSurface9_CopyDefaultToMem needs same format. */
     desc.Format = dest_surface->desc.Format;
     desc.Usage = D3DUSAGE_RENDERTARGET;
     hr = NineSurface9_new(pDevice, NineUnknown(This), temp_resource, NULL, 0,
@@ -863,7 +904,7 @@ NineSwapChain9_GetFrontBufferData( struct NineSwapChain9 *This,
 
     ID3DPresent_FrontBufferCopy(This->present, temp_handle);
 
-    NineSurface9_CopySurface(dest_surface, temp_surface, NULL, NULL);
+    NineSurface9_CopyDefaultToMem(dest_surface, temp_surface);
 
     ID3DPresent_DestroyD3DWindowBuffer(This->present, temp_handle);
     NineUnknown_Destroy(NineUnknown(temp_surface));
@@ -880,8 +921,9 @@ NineSwapChain9_GetBackBuffer( struct NineSwapChain9 *This,
     DBG("GetBackBuffer: This=%p iBackBuffer=%d Type=%d ppBackBuffer=%p\n",
         This, iBackBuffer, Type, ppBackBuffer);
     (void)user_error(Type == D3DBACKBUFFER_TYPE_MONO);
+    /* don't touch ppBackBuffer on error */
+    user_assert(ppBackBuffer != NULL, D3DERR_INVALIDCALL);
     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];
@@ -963,3 +1005,13 @@ NineSwapChain9_new( struct NineDevice9 *pDevice,
                           implicit, pPresent, pPresentationParameters,
                           pCTX, hFocusWindow, NULL);
 }
+
+BOOL
+NineSwapChain9_GetOccluded( struct NineSwapChain9 *This )
+{
+    if (This->base.device->minor_version_num > 0) {
+        return ID3DPresent_GetWindowOccluded(This->present);
+    }
+
+    return FALSE;
+}