From 49c53fd280b74f287b040a8bc62422f3ce75b008 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 31 May 2014 11:37:12 -0700 Subject: [PATCH] Use D3D9Ex when available This hopefully works around crashes in Intel D3D9 support in Windows 8.1. --- src/render/direct3d/SDL_render_d3d.c | 314 +++++++++++++++------------ src/video/windows/SDL_windowsvideo.c | 43 ++-- 2 files changed, 208 insertions(+), 149 deletions(-) diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c index 74dce2bd5..896af233b 100644 --- a/src/render/direct3d/SDL_render_d3d.c +++ b/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(); - } - data->scaleMode = GetScaleQuality(); - - texture->driverdata = data; - -#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; - } - - result = - IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, - texture->h, 1, usage, - PixelFormatToD3DFMT(texture->format), - pool, &data->texture, NULL); + result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage, + 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 (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()", 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); + return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", 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_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h) +{ + HRESULT result; + + if (!texture->texture) { + return 0; + } + + 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(D3DPOOL_DEFAULT)", 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_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_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + D3D_TextureData *texturedata; + DWORD usage; + + texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata)); + if (!texturedata) { + return SDL_OutOfMemory(); + } + texturedata->scaleMode = GetScaleQuality(); + + 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_TextureData *data = (D3D_TextureData *) texture->driverdata; - SDL_bool full_texture = SDL_FALSE; + D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; + D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; -#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 - - 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, 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; + D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata; + D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; -#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 - - 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; diff --git a/src/video/windows/SDL_windowsvideo.c b/src/video/windows/SDL_windowsvideo.c index 9ab1f4c1a..13738b92f 100644 --- a/src/video/windows/SDL_windowsvideo.c +++ b/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); + typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t) (UINT SDKVersion); + typedef HRESULT *(WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D); + Direct3DCreate9_t Direct3DCreate9Func; + Direct3DCreate9Ex_t Direct3DCreate9ExFunc; - D3DCreate = - (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(*pD3DDLL, - "Direct3DCreate9"); - if (D3DCreate) { - *pDirect3D9Interface = D3DCreate(D3D_SDK_VERSION); - } - if (!*pDirect3D9Interface) { - SDL_UnloadObject(*pD3DDLL); - *pD3DDLL = NULL; - return SDL_FALSE; + 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; + } + } } - return SDL_TRUE; - } else { - *pDirect3D9Interface = NULL; - return SDL_FALSE; + Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9"); + if (Direct3DCreate9Func) { + *pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION); + if (*pDirect3D9Interface) { + return SDL_TRUE; + } + } + + SDL_UnloadObject(*pD3DDLL); + *pD3DDLL = NULL; } + *pDirect3D9Interface = NULL; + return SDL_FALSE; }