[1/X] WineD3D: Implement IWineD3DDevice::Reset

Stefan Dösinger stefan at codeweavers.com
Fri Dec 8 09:13:15 CST 2006


This part implements IWineD3DDevice::Reset to allow games to change the 
resolution. It also adds a test to check the effect of Reset on the viewport 
and swapchain presentation parameters.

This patch should be independent of the new wave of state management patches 
I'm going to send, but I'm marking it as the first patch.
-------------- next part --------------
From 2c2e57ef1251b84141e5d7ec034f0497cafdfcc5 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Fri, 8 Dec 2006 15:44:54 +0100
Subject: [PATCH] WineD3D: Implement IWineD3DDevice::Reset

---
 dlls/d3d9/tests/device.c       |  145 ++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c          |  154 ++++++++++++++++++++++++++++++++++++++--
 dlls/wined3d/wined3d_private.h |    1 
 3 files changed, 294 insertions(+), 6 deletions(-)

diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c
index 93f0f90..a1336f2 100644
--- a/dlls/d3d9/tests/device.c
+++ b/dlls/d3d9/tests/device.c
@@ -687,6 +687,150 @@ static void test_cursor(void)
     ok(info.hCursor == cur, "The cursor handle is %p\n", info.hCursor); /* unchanged */
 
 cleanup:
+    if(pDevice) IDirect3D9_Release(pDevice);
+    if(pD3d) IDirect3D9_Release(pD3d);
+    DestroyWindow( hwnd );
+}
+
+static void test_reset(void)
+{
+    HRESULT                      hr;
+    HWND                         hwnd               = NULL;
+    IDirect3D9                  *pD3d               = NULL;
+    IDirect3DDevice9            *pDevice            = NULL;
+    D3DPRESENT_PARAMETERS        d3dpp;
+    D3DDISPLAYMODE               d3ddm;
+    D3DVIEWPORT9                 vp;
+    DWORD                        width, orig_width = GetSystemMetrics(SM_CXSCREEN);
+    DWORD                        height, orig_height = GetSystemMetrics(SM_CYSCREEN);
+    IDirect3DSwapChain9          *pSwapchain;
+
+    pD3d = pDirect3DCreate9( D3D_SDK_VERSION );
+    ok(pD3d != NULL, "Failed to create IDirect3D9 object\n");
+    hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL );
+    ok(hwnd != NULL, "Failed to create window\n");
+    if (!pD3d || !hwnd) goto cleanup;
+
+    IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm );
+    ZeroMemory( &d3dpp, sizeof(d3dpp) );
+    d3dpp.Windowed         = FALSE;
+    d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
+    d3dpp.BackBufferWidth  = 800;
+    d3dpp.BackBufferHeight  = 600;
+    d3dpp.BackBufferFormat = d3ddm.Format;
+
+    hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd,
+                                  D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
+    ok(SUCCEEDED(hr), "Failed to create IDirect3D9Device (%s)\n", DXGetErrorString9(hr));
+    if (FAILED(hr)) goto cleanup;
+
+    width = GetSystemMetrics(SM_CXSCREEN);
+    height = GetSystemMetrics(SM_CYSCREEN);
+    ok(width == 800, "Screen width is %d\n", width);
+    ok(height == 600, "Screen height is %d\n", height);
+
+    hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
+    if(SUCCEEDED(hr))
+    {
+        ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
+        ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
+        ok(vp.Width == 800, "D3DVIEWPORT->X = %d\n", vp.Width);
+        ok(vp.Height == 600, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
+    }
+    vp.X = 10;
+    vp.X = 20;
+    vp.MinZ = 2;
+    vp.MaxZ = 3;
+    hr = IDirect3DDevice9_SetViewport(pDevice, &vp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_SetViewport failed with %s\n", DXGetErrorString9(hr));
+
+    ZeroMemory( &d3dpp, sizeof(d3dpp) );
+    d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
+    d3dpp.Windowed         = FALSE;
+    d3dpp.BackBufferWidth  = 640;
+    d3dpp.BackBufferHeight  = 480;
+    d3dpp.BackBufferFormat = d3ddm.Format;
+    hr = IDirect3DDevice9_Reset(pDevice, &d3dpp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr));
+
+    ZeroMemory(&vp, sizeof(vp));
+    hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
+    if(SUCCEEDED(hr))
+    {
+        ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
+        ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
+        ok(vp.Width == 640, "D3DVIEWPORT->X = %d\n", vp.Width);
+        ok(vp.Height == 480, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
+    }
+
+    width = GetSystemMetrics(SM_CXSCREEN);
+    height = GetSystemMetrics(SM_CYSCREEN);
+    ok(width == 640, "Screen width is %d\n", width);
+    ok(height == 480, "Screen height is %d\n", height);
+
+    hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &pSwapchain);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetSwapChain returned %s\n", DXGetErrorString9(hr));
+    if(SUCCEEDED(hr))
+    {
+        ZeroMemory(&d3dpp, sizeof(d3dpp));
+        hr = IDirect3DSwapChain9_GetPresentParameters(pSwapchain, &d3dpp);
+        ok(hr == D3D_OK, "IDirect3DSwapChain9_GetPresentParameters returned %s\n", DXGetErrorString9(hr));
+        if(SUCCEEDED(hr))
+        {
+            ok(d3dpp.BackBufferWidth == 640, "Back buffer width is %d\n", d3dpp.BackBufferWidth);
+            ok(d3dpp.BackBufferHeight == 480, "Back buffer height is %d\n", d3dpp.BackBufferHeight);
+        }
+        IDirect3DSwapChain9_Release(pSwapchain);
+    }
+
+    ZeroMemory( &d3dpp, sizeof(d3dpp) );
+    d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
+    d3dpp.Windowed         = TRUE;
+    d3dpp.BackBufferWidth  = 400;
+    d3dpp.BackBufferHeight  = 300;
+    hr = IDirect3DDevice9_Reset(pDevice, &d3dpp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr));
+
+    width = GetSystemMetrics(SM_CXSCREEN);
+    height = GetSystemMetrics(SM_CYSCREEN);
+    ok(width == orig_width, "Screen width is %d\n", width);
+    ok(height == orig_height, "Screen height is %d\n", height);
+
+    ZeroMemory(&vp, sizeof(vp));
+    hr = IDirect3DDevice9_GetViewport(pDevice, &vp);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetViewport failed with %s\n", DXGetErrorString9(hr));
+    if(SUCCEEDED(hr))
+    {
+        ok(vp.X == 0, "D3DVIEWPORT->X = %d\n", vp.X);
+        ok(vp.Y == 0, "D3DVIEWPORT->X = %d\n", vp.Y);
+        ok(vp.Width == 400, "D3DVIEWPORT->X = %d\n", vp.Width);
+        ok(vp.Height == 300, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MinZ == 0, "D3DVIEWPORT->X = %d\n", vp.Height);
+        ok(vp.MaxZ == 1, "D3DVIEWPORT->X = %d\n", vp.Height);
+    }
+
+    hr = IDirect3DDevice9_GetSwapChain(pDevice, 0, &pSwapchain);
+    ok(hr == D3D_OK, "IDirect3DDevice9_GetSwapChain returned %s\n", DXGetErrorString9(hr));
+    if(SUCCEEDED(hr))
+    {
+        ZeroMemory(&d3dpp, sizeof(d3dpp));
+        hr = IDirect3DSwapChain9_GetPresentParameters(pSwapchain, &d3dpp);
+        ok(hr == D3D_OK, "IDirect3DSwapChain9_GetPresentParameters returned %s\n", DXGetErrorString9(hr));
+        if(SUCCEEDED(hr))
+        {
+            ok(d3dpp.BackBufferWidth == 400, "Back buffer width is %d\n", d3dpp.BackBufferWidth);
+            ok(d3dpp.BackBufferHeight == 300, "Back buffer height is %d\n", d3dpp.BackBufferHeight);
+        }
+        IDirect3DSwapChain9_Release(pSwapchain);
+    }
+
+cleanup:
     if(pD3d) IDirect3D9_Release(pD3d);
     if(pDevice) IDirect3D9_Release(pDevice);
 }
@@ -702,5 +846,6 @@ START_TEST(device)
         test_refcount();
         test_mipmap_levels();
         test_cursor();
+        test_reset();
     }
 }
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index d8083f7..4e81c06 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1538,6 +1538,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl
         WARN("Failed to get a valid XVisuial ID for the window %p\n", object->win_handle);
         return WINED3DERR_NOTAVAILABLE;
     }
+
+    object->orig_width = GetSystemMetrics(SM_CXSCREEN);
+    object->orig_height = GetSystemMetrics(SM_CYSCREEN);
+
     /**
     * Create an opengl context for the display visual
     *  NOTE: the visual is chosen as the window is created and the glcontext cannot
@@ -7514,14 +7518,152 @@ static HRESULT  WINAPI  IWineD3DDeviceIm
     return WINED3D_OK;
 }
 
+void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
+    /* Reallocate proper memory for the front and back buffer and adjust their sizes */
+    if(surface->Flags & SFLAG_DIBSECTION) {
+        /* Release the DC */
+        SelectObject(surface->hDC, surface->dib.holdbitmap);
+        DeleteDC(surface->hDC);
+        /* Release the DIB section */
+        DeleteObject(surface->dib.DIBsection);
+        surface->dib.bitmap_data = NULL;
+        surface->resource.allocatedMemory = NULL;
+        surface->Flags &= ~SFLAG_DIBSECTION;
+    }
+    surface->currentDesc.Width = *pPresentationParameters->BackBufferWidth;
+    surface->currentDesc.Height = *pPresentationParameters->BackBufferHeight;
+    if (wined3d_settings.nonpower2_mode == NP2_NATIVE) {
+        surface->pow2Width = *pPresentationParameters->BackBufferWidth;
+        surface->pow2Height = *pPresentationParameters->BackBufferHeight;
+    } else {
+        surface->pow2Width = surface->pow2Height = 1;
+        while (surface->pow2Width < *pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
+        while (surface->pow2Height < *pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
+    }
+    if(surface->glDescription.textureName) {
+        ENTER_GL();
+        glDeleteTextures(1, &surface->glDescription.textureName);
+        LEAVE_GL();
+        surface->glDescription.textureName = 0;
+    }
+    if(surface->pow2Width != *pPresentationParameters->BackBufferWidth ||
+       surface->pow2Height != *pPresentationParameters->BackBufferHeight) {
+        surface->Flags |= SFLAG_NONPOW2;
+    } else  {
+        surface->Flags &= ~SFLAG_NONPOW2;
+    }
+    HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
+    surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
+}
+
 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
-    /** FIXME: Resource trascking needs to be done.
-    * in effect this pulls all non only default
-    * textures out of video memory and deletes all glTextures (glDeleteTextures)
-    * and should clear down the context and set it up according to pPresentationParameters
-     ***********************************************************/
-    FIXME("(%p) : stub\n", This);
+    IWineD3DSwapChainImpl *swapchain;
+    HRESULT hr;
+    BOOL DisplayModeChanged = FALSE;
+    WINED3DDISPLAYMODE mode;
+    TRACE("(%p)\n", This);
+
+    hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
+    if(FAILED(hr)) {
+        ERR("Failed to get the first implicit swapchain\n");
+        return hr;
+    }
+
+    /* Is it neccessary to recreate the gl context? Actually every setting can be changed
+     * on an existing gl context, so there's no real need for recreation.
+     *
+     * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
+     *
+     * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
+     */
+    TRACE("New params:\n");
+    TRACE("BackBufferWidth = %d\n", *pPresentationParameters->BackBufferWidth);
+    TRACE("BackBufferHeight = %d\n", *pPresentationParameters->BackBufferHeight);
+    TRACE("BackBufferFormat = %s\n", debug_d3dformat(*pPresentationParameters->BackBufferFormat));
+    TRACE("BackBufferCount = %d\n", *pPresentationParameters->BackBufferCount);
+    TRACE("MultiSampleType = %d\n", *pPresentationParameters->MultiSampleType);
+    TRACE("MultiSampleQuality = %d\n", *pPresentationParameters->MultiSampleQuality);
+    TRACE("SwapEffect = %d\n", *pPresentationParameters->SwapEffect);
+    TRACE("hDeviceWindow = %p\n", *pPresentationParameters->hDeviceWindow);
+    TRACE("Windowed = %s\n", *pPresentationParameters->Windowed ? "true" : "false");
+    TRACE("EnableAutoDepthStencil = %s\n", *pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
+    TRACE("Flags = %08x\n", *pPresentationParameters->Flags);
+    TRACE("FullScreen_RefreshRateInHz = %d\n", *pPresentationParameters->FullScreen_RefreshRateInHz);
+    TRACE("PresentationInterval = %d\n", *pPresentationParameters->PresentationInterval);
+
+    /* No special treatment of this parameters. Just store them */
+    swapchain->presentParms.SwapEffect = *pPresentationParameters->SwapEffect;
+    swapchain->presentParms.Flags = *pPresentationParameters->Flags;
+    swapchain->presentParms.PresentationInterval = *pPresentationParameters->PresentationInterval;
+    swapchain->presentParms.FullScreen_RefreshRateInHz = *pPresentationParameters->FullScreen_RefreshRateInHz;
+
+    /* What to do about these? */
+    if(*pPresentationParameters->BackBufferCount != 0 &&
+        *pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
+        ERR("Cannot change the back buffer count yet\n");
+    }
+    if(*pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
+        *pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
+        ERR("Cannot change the back buffer format yet\n");
+    }
+    if(*pPresentationParameters->hDeviceWindow != NULL &&
+        *pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
+        ERR("Cannot change the device window yet\n");
+    }
+    if(*pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
+        ERR("What do do about a changed auto depth stencil parameter?\n");
+    }
+
+    if(*pPresentationParameters->Windowed) {
+        mode.Width = swapchain->orig_width;
+        mode.Height = swapchain->orig_height;
+        mode.RefreshRate = 0;
+        mode.Format = swapchain->presentParms.BackBufferFormat;
+    } else {
+        mode.Width = *pPresentationParameters->BackBufferWidth;
+        mode.Height = *pPresentationParameters->BackBufferHeight;
+        mode.RefreshRate = *pPresentationParameters->FullScreen_RefreshRateInHz;
+        mode.Format = swapchain->presentParms.BackBufferFormat;
+    }
+
+    /* Should Width == 800 && Height == 0 set 800x600? */
+    if(*pPresentationParameters->BackBufferWidth != 0 && *pPresentationParameters->BackBufferHeight != 0 &&
+       (*pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
+        *pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
+    {
+        WINED3DVIEWPORT vp;
+        int i;
+
+        vp.X = 0;
+        vp.Y = 0;
+        vp.Width = *pPresentationParameters->BackBufferWidth;
+        vp.Height = *pPresentationParameters->BackBufferHeight;
+        vp.MinZ = 0;
+        vp.MaxZ = 1;
+
+        if(!*pPresentationParameters->Windowed) {
+            DisplayModeChanged = TRUE;
+        }
+        swapchain->presentParms.BackBufferWidth = *pPresentationParameters->BackBufferWidth;
+        swapchain->presentParms.BackBufferHeight = *pPresentationParameters->BackBufferHeight;
+
+        updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
+        for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
+            updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
+        }
+
+        /* Now set the new viewport */
+        IWineD3DDevice_SetViewport(iface, &vp);
+    }
+
+    if((*pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
+       (swapchain->presentParms.Windowed && !*pPresentationParameters->Windowed) ||
+        DisplayModeChanged) {
+        IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
+    }
+
+    IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 20d7c09..9d453b2 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1257,6 +1257,7 @@ typedef struct IWineD3DSwapChainImpl
     IWineD3DSurface          *frontBuffer;
     BOOL                      wantsDepthStencilBuffer;
     D3DPRESENT_PARAMETERS     presentParms;
+    DWORD                     orig_width, orig_height;
 
     /* TODO: move everything up to drawable off into a context manager
       and store the 'data' in the contextManagerData interface.
-- 
1.4.2.4



More information about the wine-patches mailing list