فهرست منبع

Use D3D9Ex when available
This hopefully works around crashes in Intel D3D9 support in Windows 8.1.

Sam Lantinga 12 سال پیش
والد
کامیت
49c53fd280
2فایلهای تغییر یافته به همراه205 افزوده شده و 146 حذف شده
  1. 177 131
      src/render/direct3d/SDL_render_d3d.c
  2. 28 15
      src/video/windows/SDL_windowsvideo.c

+ 177 - 131
src/render/direct3d/SDL_render_d3d.c

@@ -124,6 +124,7 @@ static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
 static void D3D_WindowEvent(SDL_Renderer * renderer,
                             const SDL_WindowEvent *event);
 static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                              const SDL_Rect * rect, const void *pixels,
                              int pitch);
@@ -190,12 +191,18 @@ typedef struct
 typedef struct
 {
     IDirect3DTexture9 *texture;
+    IDirect3DTexture9 *staging;
+} D3D_TextureRep;
+
+typedef struct
+{
+    D3D_TextureRep texture;
     D3DTEXTUREFILTERTYPE scaleMode;
 
     /* YV12 texture support */
     SDL_bool yuv;
-    IDirect3DTexture9 *utexture;
-    IDirect3DTexture9 *vtexture;
+    D3D_TextureRep utexture;
+    D3D_TextureRep vtexture;
     Uint8 *pixels;
     int pitch;
     SDL_Rect locked_rect;
@@ -408,6 +415,8 @@ D3D_Reset(SDL_Renderer * renderer)
     for (texture = renderer->textures; texture; texture = texture->next) {
         if (texture->access == SDL_TEXTUREACCESS_TARGET) {
             D3D_DestroyTexture(renderer, texture);
+        } else {
+            D3D_RecreateTexture(renderer, texture);
         }
     }
 
@@ -805,74 +814,58 @@ GetScaleQuality(void)
 }
 
 static int
-D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
 {
-    D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
-    D3D_TextureData *data;
-    D3DPOOL pool;
-    DWORD usage;
     HRESULT result;
 
-    data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data));
-    if (!data) {
-        return SDL_OutOfMemory();
+    result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
+        PixelFormatToD3DFMT(format),
+        D3DPOOL_DEFAULT, &texture->texture, NULL);
+    if (FAILED(result)) {
+        return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
     }
-    data->scaleMode = GetScaleQuality();
 
-    texture->driverdata = data;
+    if (usage != D3DUSAGE_RENDERTARGET) {
+        result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
+            PixelFormatToD3DFMT(format),
+            D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
+        if (FAILED(result)) {
+            return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
+        }
+    }
+    return 0;
+}
 
-#ifdef USE_DYNAMIC_TEXTURE
-    if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
-        pool = D3DPOOL_DEFAULT;
-        usage = D3DUSAGE_DYNAMIC;
-    } else
-#endif
-    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
-        /* D3DPOOL_MANAGED does not work with D3DUSAGE_RENDERTARGET */
-        pool = D3DPOOL_DEFAULT;
-        usage = D3DUSAGE_RENDERTARGET;
-    } else {
-        pool = D3DPOOL_MANAGED;
-        usage = 0;
+static int
+D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
+{
+    HRESULT result;
+
+    if (!texture->texture) {
+        return 0;
     }
 
-    result =
-        IDirect3DDevice9_CreateTexture(renderdata->device, texture->w,
-                                       texture->h, 1, usage,
-                                       PixelFormatToD3DFMT(texture->format),
-                                       pool, &data->texture, NULL);
+    IDirect3DTexture9_Release(texture->texture);
+    result = IDirect3DDevice9_CreateTexture(device, w, h, 1, 0,
+        PixelFormatToD3DFMT(format),
+        D3DPOOL_DEFAULT, &texture->texture, NULL);
     if (FAILED(result)) {
-        return D3D_SetError("CreateTexture()", result);
+        return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
     }
 
-    if (texture->format == SDL_PIXELFORMAT_YV12 ||
-        texture->format == SDL_PIXELFORMAT_IYUV) {
-        data->yuv = SDL_TRUE;
-
-        result =
-            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
-                                           texture->h / 2, 1, usage,
-                                           PixelFormatToD3DFMT(texture->format),
-                                           pool, &data->utexture, NULL);
-        if (FAILED(result)) {
-            return D3D_SetError("CreateTexture()", result);
-        }
-
-        result =
-            IDirect3DDevice9_CreateTexture(renderdata->device, texture->w / 2,
-                                           texture->h / 2, 1, usage,
-                                           PixelFormatToD3DFMT(texture->format),
-                                           pool, &data->vtexture, NULL);
-        if (FAILED(result)) {
-            return D3D_SetError("CreateTexture()", result);
-        }
+    result = IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
+    if (FAILED(result)) {
+        return D3D_SetError("AddDirtyRect()", result);
+    }
+    result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
+    if (FAILED(result)) {
+        return D3D_SetError("UpdateTexture()", result);
     }
-
     return 0;
 }
 
 static int
-D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool full_texture, int x, int y, int w, int h, const void *pixels, int pitch)
+D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
 {
     RECT d3drect;
     D3DLOCKED_RECT locked;
@@ -881,16 +874,11 @@ D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool fu
     int row, length;
     HRESULT result;
 
-    if (full_texture) {
-        result = IDirect3DTexture9_LockRect(texture, 0, &locked, NULL, D3DLOCK_DISCARD);
-    } else {
-        d3drect.left = x;
-        d3drect.right = x + w;
-        d3drect.top = y;
-        d3drect.bottom = y + h;
-        result = IDirect3DTexture9_LockRect(texture, 0, &locked, &d3drect, 0);
-    }
-
+    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);
     }
@@ -913,46 +901,114 @@ D3D_UpdateTextureInternal(IDirect3DTexture9 *texture, Uint32 format, SDL_bool fu
             dst += locked.Pitch;
         }
     }
-    IDirect3DTexture9_UnlockRect(texture, 0);
+    IDirect3DTexture9_UnlockRect(texture->staging, 0);
+    IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
 
     return 0;
 }
 
+static void
+D3D_DestroyTextureRep(D3D_TextureRep *texture)
+{
+    if (texture->texture) {
+        IDirect3DTexture9_Release(texture->texture);
+        texture->texture = NULL;
+    }
+    if (texture->staging) {
+        IDirect3DTexture9_Release(texture->staging);
+        texture->staging = NULL;
+    }
+}
+
 static int
-D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
-                  const SDL_Rect * rect, const void *pixels, int pitch)
+D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
-    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
-    SDL_bool full_texture = SDL_FALSE;
+    D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
+    D3D_TextureData *texturedata;
+    DWORD usage;
 
-#ifdef USE_DYNAMIC_TEXTURE
-    if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
-        rect->x == 0 && rect->y == 0 &&
-        rect->w == texture->w && rect->h == texture->h) {
-        full_texture = SDL_TRUE;
+    texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
+    if (!texturedata) {
+        return SDL_OutOfMemory();
     }
-#endif
+    texturedata->scaleMode = GetScaleQuality();
 
-    if (!data) {
+    texture->driverdata = texturedata;
+
+    if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+        usage = D3DUSAGE_RENDERTARGET;
+    } else {
+        usage = 0;
+    }
+
+    if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
+        return -1;
+    }
+
+    if (texture->format == SDL_PIXELFORMAT_YV12 ||
+        texture->format == SDL_PIXELFORMAT_IYUV) {
+        texturedata->yuv = SDL_TRUE;
+
+        if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
+            return -1;
+        }
+
+        if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int
+D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
+    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
+
+    if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
+        return -1;
+    }
+
+    if (texturedata->yuv) {
+        if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
+            return -1;
+        }
+
+        if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+static int
+D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+                  const SDL_Rect * rect, const void *pixels, int pitch)
+{
+    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
+    D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
+
+    if (!texturedata) {
         SDL_SetError("Texture is not currently available");
         return -1;
     }
 
-    if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
+    if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
         return -1;
     }
 
-    if (data->yuv) {
+    if (texturedata->yuv) {
         /* Skip to the correct offset into the next texture */
         pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
 
-        if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->vtexture : data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
+        if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
             return -1;
         }
 
         /* Skip to the correct offset into the next texture */
         pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
-        if (D3D_UpdateTextureInternal(texture->format == SDL_PIXELFORMAT_YV12 ? data->utexture : data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
+        if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
             return -1;
         }
     }
@@ -966,29 +1022,21 @@ D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
                      const Uint8 *Uplane, int Upitch,
                      const Uint8 *Vplane, int Vpitch)
 {
-    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
-    SDL_bool full_texture = SDL_FALSE;
-
-#ifdef USE_DYNAMIC_TEXTURE
-    if (texture->access == SDL_TEXTUREACCESS_STREAMING &&
-        rect->x == 0 && rect->y == 0 &&
-        rect->w == texture->w && rect->h == texture->h) {
-            full_texture = SDL_TRUE;
-    }
-#endif
+    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
+    D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
 
-    if (!data) {
+    if (!texturedata) {
         SDL_SetError("Texture is not currently available");
         return -1;
     }
 
-    if (D3D_UpdateTextureInternal(data->texture, texture->format, full_texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
+    if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
         return -1;
     }
-    if (D3D_UpdateTextureInternal(data->utexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
+    if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
         return -1;
     }
-    if (D3D_UpdateTextureInternal(data->vtexture, texture->format, full_texture, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
+    if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
         return -1;
     }
     return 0;
@@ -998,37 +1046,39 @@ static int
 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
                 const SDL_Rect * rect, void **pixels, int *pitch)
 {
-    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
-    RECT d3drect;
-    D3DLOCKED_RECT locked;
-    HRESULT result;
+    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
 
-    if (!data) {
+    if (!texturedata) {
         SDL_SetError("Texture is not currently available");
         return -1;
     }
 
-    if (data->yuv) {
+    texturedata->locked_rect = *rect;
+
+    if (texturedata->yuv) {
         /* It's more efficient to upload directly... */
-        if (!data->pixels) {
-            data->pitch = texture->w;
-            data->pixels = (Uint8 *)SDL_malloc((texture->h * data->pitch * 3) / 2);
-            if (!data->pixels) {
+        if (!texturedata->pixels) {
+            texturedata->pitch = texture->w;
+            texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
+            if (!texturedata->pixels) {
                 return SDL_OutOfMemory();
             }
         }
-        data->locked_rect = *rect;
         *pixels =
-            (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
+            (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
                       rect->x * SDL_BYTESPERPIXEL(texture->format));
-        *pitch = data->pitch;
+        *pitch = texturedata->pitch;
     } else {
+        RECT d3drect;
+        D3DLOCKED_RECT locked;
+        HRESULT result;
+
         d3drect.left = rect->x;
         d3drect.right = rect->x + rect->w;
         d3drect.top = rect->y;
         d3drect.bottom = rect->y + rect->h;
 
-        result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0);
+        result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
         if (FAILED(result)) {
             return D3D_SetError("LockRect()", result);
         }
@@ -1041,20 +1091,22 @@ D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
 static void
 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
 {
-    D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
+    D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
+    D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
 
-    if (!data) {
+    if (!texturedata) {
         return;
     }
 
-    if (data->yuv) {
-        const SDL_Rect *rect = &data->locked_rect;
+    if (texturedata->yuv) {
+        const SDL_Rect *rect = &texturedata->locked_rect;
         void *pixels =
-            (void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
+            (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
                       rect->x * SDL_BYTESPERPIXEL(texture->format));
-        D3D_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
+        D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
     } else {
-        IDirect3DTexture9_UnlockRect(data->texture, 0);
+        IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
+        IDirect3DDevice9_UpdateTexture(data->device, (IDirect3DBaseTexture9 *)texturedata->texture.staging, (IDirect3DBaseTexture9 *)texturedata->texture.texture);
     }
 }
 
@@ -1082,7 +1134,7 @@ D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
         return -1;
     }
 
-    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture, 0, &data->currentRenderTarget);
+    result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
     if(FAILED(result)) {
         return D3D_SetError("GetSurfaceLevel()", result);
     }
@@ -1530,7 +1582,7 @@ D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
 
     result =
         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
-                                    texturedata->texture);
+                                    texturedata->texture.texture);
     if (FAILED(result)) {
         return D3D_SetError("SetTexture()", result);
     }
@@ -1543,14 +1595,14 @@ D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
 
         result =
             IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
-                                        texturedata->utexture);
+                                        texturedata->utexture.texture);
         if (FAILED(result)) {
             return D3D_SetError("SetTexture()", result);
         }
 
         result =
             IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
-                                        texturedata->vtexture);
+                                        texturedata->vtexture.texture);
         if (FAILED(result)) {
             return D3D_SetError("SetTexture()", result);
         }
@@ -1673,7 +1725,7 @@ D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
 
     result =
         IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *)
-                                    texturedata->texture);
+                                    texturedata->texture.texture);
     if (FAILED(result)) {
         return D3D_SetError("SetTexture()", result);
     }
@@ -1686,14 +1738,14 @@ D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
 
         result =
             IDirect3DDevice9_SetTexture(data->device, 1, (IDirect3DBaseTexture9 *)
-                                        texturedata->utexture);
+                                        texturedata->utexture.texture);
         if (FAILED(result)) {
             return D3D_SetError("SetTexture()", result);
         }
 
         result =
             IDirect3DDevice9_SetTexture(data->device, 2, (IDirect3DBaseTexture9 *)
-                                        texturedata->vtexture);
+                                        texturedata->vtexture.texture);
         if (FAILED(result)) {
             return D3D_SetError("SetTexture()", result);
         }
@@ -1816,15 +1868,9 @@ D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
     if (!data) {
         return;
     }
-    if (data->texture) {
-        IDirect3DTexture9_Release(data->texture);
-    }
-    if (data->utexture) {
-        IDirect3DTexture9_Release(data->utexture);
-    }
-    if (data->vtexture) {
-        IDirect3DTexture9_Release(data->vtexture);
-    }
+    D3D_DestroyTextureRep(&data->texture);
+    D3D_DestroyTextureRep(&data->utexture);
+    D3D_DestroyTextureRep(&data->vtexture);
     SDL_free(data->pixels);
     SDL_free(data);
     texture->driverdata = NULL;

+ 28 - 15
src/video/windows/SDL_windowsvideo.c

@@ -184,25 +184,38 @@ D3D_LoadDLL( void **pD3DDLL, IDirect3D9 **pDirect3D9Interface )
 {
     *pD3DDLL = SDL_LoadObject("D3D9.DLL");
     if (*pD3DDLL) {
-        IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion);
-
-        D3DCreate =
-            (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(*pD3DDLL,
-            "Direct3DCreate9");
-        if (D3DCreate) {
-            *pDirect3D9Interface = D3DCreate(D3D_SDK_VERSION);
+        typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t) (UINT SDKVersion);
+        typedef HRESULT *(WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D);
+        Direct3DCreate9_t Direct3DCreate9Func;
+        Direct3DCreate9Ex_t Direct3DCreate9ExFunc;
+
+        Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex");
+        if (Direct3DCreate9ExFunc) {
+            IDirect3D9Ex *pDirect3D9ExInterface;
+            HRESULT hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
+            if (SUCCEEDED(hr)) {
+                const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } };
+                hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (LPVOID)pDirect3D9Interface);
+                IDirect3D9Ex_Release(pDirect3D9ExInterface);
+                if (SUCCEEDED(hr)) {
+                    return SDL_TRUE;
+                }
+            }
         }
-        if (!*pDirect3D9Interface) {
-            SDL_UnloadObject(*pD3DDLL);
-            *pD3DDLL = NULL;
-            return SDL_FALSE;
+
+        Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9");
+        if (Direct3DCreate9Func) {
+            *pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION);
+            if (*pDirect3D9Interface) {
+                return SDL_TRUE;
+            }
         }
 
-        return SDL_TRUE;
-    } else {
-        *pDirect3D9Interface = NULL;
-        return SDL_FALSE;
+        SDL_UnloadObject(*pD3DDLL);
+        *pD3DDLL = NULL;
     }
+    *pDirect3D9Interface = NULL;
+    return SDL_FALSE;
 }