Commit d673d8c3892a812dbc1ade984543a331e9b5acc8

Sam Lantinga 2014-08-16T23:17:47

Fixed bugs 2677 and 2625, made it possible to lock render targets in D3D

diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 6927985..be88da3 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -193,6 +193,9 @@ typedef struct
 typedef struct
 {
     SDL_bool dirty;
+    int w, h;
+    DWORD usage;
+    Uint32 format;
     IDirect3DTexture9 *texture;
     IDirect3DTexture9 *staging;
 } D3D_TextureRep;
@@ -819,6 +822,10 @@ D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD us
     HRESULT result;
 
     texture->dirty = SDL_FALSE;
+    texture->w = w;
+    texture->h = h;
+    texture->usage = usage;
+    texture->format = format;
 
     result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
         PixelFormatToD3DFMT(format),
@@ -826,10 +833,18 @@ D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD us
     if (FAILED(result)) {
         return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
     }
+    return 0;
+}
+
+
+static int
+D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
+{
+    HRESULT result;
 
-    if (usage != D3DUSAGE_RENDERTARGET) {
-        result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
-            PixelFormatToD3DFMT(format),
+    if (texture->staging == NULL) {
+        result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
+            PixelFormatToD3DFMT(texture->format),
             D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
         if (FAILED(result)) {
             return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
@@ -845,14 +860,8 @@ D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD samp
 
     if (texture->dirty && texture->staging) {
         if (!texture->texture) {
-            D3DSURFACE_DESC desc;
-            result = IDirect3DTexture9_GetLevelDesc(texture->staging, 0, &desc);
-            if (FAILED(result)) {
-                return D3D_SetError("GetLevelDesc", result);
-            }
-
-            result = IDirect3DDevice9_CreateTexture(device, desc.Width, desc.Height, 1, 0,
-                desc.Format, D3DPOOL_DEFAULT, &texture->texture, NULL);
+            result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
+                PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
             if (FAILED(result)) {
                 return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
             }
@@ -878,8 +887,10 @@ D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32
         IDirect3DTexture9_Release(texture->texture);
         texture->texture = NULL;
     }
-    IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
-    texture->dirty = SDL_TRUE;
+    if (texture->staging) {
+        IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
+        texture->dirty = SDL_TRUE;
+    }
     return 0;
 }
 
@@ -893,10 +904,15 @@ D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 f
     int row, length;
     HRESULT result;
 
+    if (D3D_CreateStagingTexture(device, texture) < 0) {
+        return -1;
+    }
+
     d3drect.left = x;
     d3drect.right = x + w;
     d3drect.top = y;
     d3drect.bottom = y + h;
+    
     result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
     if (FAILED(result)) {
         return D3D_SetError("LockRect()", result);
@@ -1068,7 +1084,9 @@ static int
 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                 const SDL_Rect * rect, void **pixels, int *pitch)
 {
+    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
     D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
+    IDirect3DDevice9 *device = data->device;
 
     if (!texturedata) {
         SDL_SetError("Texture is not currently available");
@@ -1095,6 +1113,10 @@ D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
         D3DLOCKED_RECT locked;
         HRESULT result;
 
+        if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
+            return -1;
+        }
+
         d3drect.left = rect->x;
         d3drect.right = rect->x + rect->w;
         d3drect.top = rect->y;
@@ -1137,7 +1159,9 @@ D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
 {
     D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
     D3D_TextureData *texturedata;
+    D3D_TextureRep *texturerep;
     HRESULT result;
+    IDirect3DDevice9 *device = data->device;
 
     /* Release the previous render target if it wasn't the default one */
     if (data->currentRenderTarget != NULL) {
@@ -1156,6 +1180,24 @@ D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
         return -1;
     }
 
+    /* Make sure the render target is updated if it was locked and written to */
+    texturerep = &texturedata->texture;
+    if (texturerep->dirty && texturerep->staging) {
+        if (!texturerep->texture) {
+            result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
+                PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
+            if (FAILED(result)) {
+                return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
+            }
+        }
+
+        result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
+        if (FAILED(result)) {
+            return D3D_SetError("UpdateTexture()", result);
+        }
+        texturerep->dirty = SDL_FALSE;
+    }
+
     result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
     if(FAILED(result)) {
         return D3D_SetError("GetSurfaceLevel()", result);