Mercurial > sdl-ios-xcode
view src/render/direct3d/SDL_d3drender.c @ 5157:fb424691cfc7
Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Wed, 02 Feb 2011 14:34:54 -0800 |
parents | src/video/windows/SDL_d3drender.c@be02be2ea897 |
children | 307ccc9c135e |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2010 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ #include "SDL_config.h" #if SDL_VIDEO_RENDER_D3D #include "../../core/windows/SDL_windows.h" #include "SDL_loadso.h" #include "SDL_syswm.h" #include "../SDL_sysrender.h" #include "../../video/SDL_yuv_sw_c.h" #if SDL_VIDEO_RENDER_D3D #define D3D_DEBUG_INFO #include <d3d9.h> #endif #ifdef ASSEMBLE_SHADER /////////////////////////////////////////////////////////////////////////// // ID3DXBuffer: // ------------ // The buffer object is used by D3DX to return arbitrary size data. // // GetBufferPointer - // Returns a pointer to the beginning of the buffer. // // GetBufferSize - // Returns the size of the buffer, in bytes. /////////////////////////////////////////////////////////////////////////// typedef interface ID3DXBuffer ID3DXBuffer; typedef interface ID3DXBuffer *LPD3DXBUFFER; // {8BA5FB08-5195-40e2-AC58-0D989C3A0102} DEFINE_GUID(IID_ID3DXBuffer, 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2); #undef INTERFACE #define INTERFACE ID3DXBuffer typedef interface ID3DXBuffer { const struct ID3DXBufferVtbl FAR* lpVtbl; } ID3DXBuffer; typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl; const struct ID3DXBufferVtbl { // IUnknown STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE; STDMETHOD_(ULONG, AddRef)(THIS) PURE; STDMETHOD_(ULONG, Release)(THIS) PURE; // ID3DXBuffer STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE; STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE; }; HRESULT WINAPI D3DXAssembleShader( LPCSTR pSrcData, UINT SrcDataLen, CONST LPVOID* pDefines, LPVOID pInclude, DWORD Flags, LPD3DXBUFFER* ppShader, LPD3DXBUFFER* ppErrorMsgs); #endif /* ASSEMBLE_SHADER */ /* Direct3D renderer implementation */ #if 1 /* This takes more memory but you won't lose your texture data */ #define D3DPOOL_SDL D3DPOOL_MANAGED #define SDL_MEMORY_POOL_MANAGED #else #define D3DPOOL_SDL D3DPOOL_DEFAULT #define SDL_MEMORY_POOL_DEFAULT #endif static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); static int D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch); static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, const void *pixels, int pitch); static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, int markDirty, void **pixels, int *pitch); static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, const SDL_Rect * rects); static int D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, int count); static int D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, int count); static int D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count); static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect); static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch); static int D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, const void * pixels, int pitch); static void D3D_RenderPresent(SDL_Renderer * renderer); static void D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); static void D3D_DestroyRenderer(SDL_Renderer * renderer); SDL_RenderDriver D3D_RenderDriver = { D3D_CreateRenderer, { "d3d", (SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED), 0, {0}, 0, 0} }; typedef struct { void* d3dDLL; IDirect3D9 *d3d; IDirect3DDevice9 *device; UINT adapter; D3DPRESENT_PARAMETERS pparams; SDL_bool beginScene; } D3D_RenderData; typedef struct { SDL_SW_YUVTexture *yuv; Uint32 format; IDirect3DTexture9 *texture; } D3D_TextureData; typedef struct { float x, y, z; float rhw; DWORD color; float u, v; } Vertex; static void D3D_SetError(const char *prefix, HRESULT result) { const char *error; switch (result) { case D3DERR_WRONGTEXTUREFORMAT: error = "WRONGTEXTUREFORMAT"; break; case D3DERR_UNSUPPORTEDCOLOROPERATION: error = "UNSUPPORTEDCOLOROPERATION"; break; case D3DERR_UNSUPPORTEDCOLORARG: error = "UNSUPPORTEDCOLORARG"; break; case D3DERR_UNSUPPORTEDALPHAOPERATION: error = "UNSUPPORTEDALPHAOPERATION"; break; case D3DERR_UNSUPPORTEDALPHAARG: error = "UNSUPPORTEDALPHAARG"; break; case D3DERR_TOOMANYOPERATIONS: error = "TOOMANYOPERATIONS"; break; case D3DERR_CONFLICTINGTEXTUREFILTER: error = "CONFLICTINGTEXTUREFILTER"; break; case D3DERR_UNSUPPORTEDFACTORVALUE: error = "UNSUPPORTEDFACTORVALUE"; break; case D3DERR_CONFLICTINGRENDERSTATE: error = "CONFLICTINGRENDERSTATE"; break; case D3DERR_UNSUPPORTEDTEXTUREFILTER: error = "UNSUPPORTEDTEXTUREFILTER"; break; case D3DERR_CONFLICTINGTEXTUREPALETTE: error = "CONFLICTINGTEXTUREPALETTE"; break; case D3DERR_DRIVERINTERNALERROR: error = "DRIVERINTERNALERROR"; break; case D3DERR_NOTFOUND: error = "NOTFOUND"; break; case D3DERR_MOREDATA: error = "MOREDATA"; break; case D3DERR_DEVICELOST: error = "DEVICELOST"; break; case D3DERR_DEVICENOTRESET: error = "DEVICENOTRESET"; break; case D3DERR_NOTAVAILABLE: error = "NOTAVAILABLE"; break; case D3DERR_OUTOFVIDEOMEMORY: error = "OUTOFVIDEOMEMORY"; break; case D3DERR_INVALIDDEVICE: error = "INVALIDDEVICE"; break; case D3DERR_INVALIDCALL: error = "INVALIDCALL"; break; case D3DERR_DRIVERINVALIDCALL: error = "DRIVERINVALIDCALL"; break; case D3DERR_WASSTILLDRAWING: error = "WASSTILLDRAWING"; break; default: error = "UNKNOWN"; break; } SDL_SetError("%s: %s", prefix, error); } static D3DFORMAT PixelFormatToD3DFMT(Uint32 format) { switch (format) { case SDL_PIXELFORMAT_INDEX8: return D3DFMT_P8; case SDL_PIXELFORMAT_RGB332: return D3DFMT_R3G3B2; case SDL_PIXELFORMAT_RGB444: return D3DFMT_X4R4G4B4; case SDL_PIXELFORMAT_RGB555: return D3DFMT_X1R5G5B5; case SDL_PIXELFORMAT_ARGB4444: return D3DFMT_A4R4G4B4; case SDL_PIXELFORMAT_ARGB1555: return D3DFMT_A1R5G5B5; case SDL_PIXELFORMAT_RGB565: return D3DFMT_R5G6B5; case SDL_PIXELFORMAT_RGB888: return D3DFMT_X8R8G8B8; case SDL_PIXELFORMAT_ARGB8888: return D3DFMT_A8R8G8B8; case SDL_PIXELFORMAT_ARGB2101010: return D3DFMT_A2R10G10B10; case SDL_PIXELFORMAT_YV12: return MAKEFOURCC('Y','V','1','2'); case SDL_PIXELFORMAT_IYUV: return MAKEFOURCC('I','4','2','0'); case SDL_PIXELFORMAT_UYVY: return D3DFMT_UYVY; case SDL_PIXELFORMAT_YUY2: return D3DFMT_YUY2; default: return D3DFMT_UNKNOWN; } } static SDL_bool D3D_IsTextureFormatAvailable(IDirect3D9 * d3d, UINT adapter, D3DFORMAT display_format, D3DFORMAT texture_format) { HRESULT result; result = IDirect3D9_CheckDeviceFormat(d3d, adapter, D3DDEVTYPE_HAL, display_format, 0, D3DRTYPE_TEXTURE, texture_format); return FAILED(result) ? SDL_FALSE : SDL_TRUE; } static void UpdateYUVTextureData(SDL_Texture * texture) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; SDL_Rect rect; RECT d3drect; D3DLOCKED_RECT locked; HRESULT result; d3drect.left = 0; d3drect.right = texture->w; d3drect.top = 0; d3drect.bottom = texture->h; result = IDirect3DTexture9_LockRect(data->texture, 0, &locked, &d3drect, 0); if (FAILED(result)) { return; } rect.x = 0; rect.y = 0; rect.w = texture->w; rect.h = texture->h; SDL_SW_CopyYUVToRGB(data->yuv, &rect, data->format, texture->w, texture->h, locked.pBits, locked.Pitch); IDirect3DTexture9_UnlockRect(data->texture, 0); } static void D3D_AddTextureFormats(D3D_RenderData *data, SDL_RendererInfo *info) { int i; int formats[] = { SDL_PIXELFORMAT_RGB332, SDL_PIXELFORMAT_RGB444, SDL_PIXELFORMAT_RGB555, SDL_PIXELFORMAT_ARGB4444, SDL_PIXELFORMAT_ARGB1555, SDL_PIXELFORMAT_RGB565, SDL_PIXELFORMAT_RGB888, SDL_PIXELFORMAT_ARGB8888, SDL_PIXELFORMAT_ARGB2101010, }; info->num_texture_formats = 0; for (i = 0; i < SDL_arraysize(formats); ++i) { if (D3D_IsTextureFormatAvailable (data->d3d, data->adapter, data->pparams.BackBufferFormat, PixelFormatToD3DFMT(formats[i]))) { info->texture_formats[info->num_texture_formats++] = formats[i]; } } info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YV12; info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_IYUV; info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YUY2; info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_UYVY; info->texture_formats[info->num_texture_formats++] = SDL_PIXELFORMAT_YVYU; } SDL_Renderer * D3D_CreateRenderer(SDL_Window * window, Uint32 flags) { SDL_Renderer *renderer; D3D_RenderData *data; SDL_SysWMinfo windowinfo; HRESULT result; D3DPRESENT_PARAMETERS pparams; IDirect3DSwapChain9 *chain; D3DCAPS9 caps; renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); if (!renderer) { SDL_OutOfMemory(); return NULL; } data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data)); if (!data) { SDL_free(renderer); SDL_OutOfMemory(); return NULL; } data->d3dDLL = SDL_LoadObject("D3D9.DLL"); if (data->d3dDLL) { IDirect3D9 *(WINAPI * D3DCreate) (UINT SDKVersion); D3DCreate = (IDirect3D9 * (WINAPI *) (UINT)) SDL_LoadFunction(data->d3dDLL, "Direct3DCreate9"); if (D3DCreate) { data->d3d = D3DCreate(D3D_SDK_VERSION); } if (!data->d3d) { SDL_UnloadObject(data->d3dDLL); data->d3dDLL = NULL; } } if (!data->d3d) { SDL_free(renderer); SDL_free(data); SDL_SetError("Unable to create Direct3D interface"); return NULL; } renderer->CreateTexture = D3D_CreateTexture; renderer->QueryTexturePixels = D3D_QueryTexturePixels; renderer->UpdateTexture = D3D_UpdateTexture; renderer->LockTexture = D3D_LockTexture; renderer->UnlockTexture = D3D_UnlockTexture; renderer->DirtyTexture = D3D_DirtyTexture; renderer->RenderDrawPoints = D3D_RenderDrawPoints; renderer->RenderDrawLines = D3D_RenderDrawLines; renderer->RenderFillRects = D3D_RenderFillRects; renderer->RenderCopy = D3D_RenderCopy; renderer->RenderReadPixels = D3D_RenderReadPixels; renderer->RenderWritePixels = D3D_RenderWritePixels; renderer->RenderPresent = D3D_RenderPresent; renderer->DestroyTexture = D3D_DestroyTexture; renderer->DestroyRenderer = D3D_DestroyRenderer; renderer->info = D3D_RenderDriver.info; renderer->window = window; renderer->driverdata = data; renderer->info.flags = SDL_RENDERER_ACCELERATED; SDL_VERSION(&windowinfo.version); SDL_GetWindowWMInfo(window, &windowinfo); SDL_zero(pparams); pparams.hDeviceWindow = windowinfo.info.win.window; pparams.BackBufferWidth = window->w; pparams.BackBufferHeight = window->h; if (window->flags & SDL_WINDOW_FULLSCREEN) { pparams.BackBufferFormat = PixelFormatToD3DFMT(window->fullscreen_mode.format); } else { pparams.BackBufferFormat = D3DFMT_UNKNOWN; } pparams.BackBufferCount = 1; pparams.SwapEffect = D3DSWAPEFFECT_DISCARD; if (window->flags & SDL_WINDOW_FULLSCREEN) { pparams.Windowed = FALSE; pparams.FullScreen_RefreshRateInHz = window->fullscreen_mode.refresh_rate; } else { pparams.Windowed = TRUE; pparams.FullScreen_RefreshRateInHz = 0; } if (flags & SDL_RENDERER_PRESENTVSYNC) { pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE; } else { pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; } /* FIXME: Which adapter? */ data->adapter = D3DADAPTER_DEFAULT; IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); result = IDirect3D9_CreateDevice(data->d3d, data->adapter, D3DDEVTYPE_HAL, pparams.hDeviceWindow, (caps. DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? D3DCREATE_HARDWARE_VERTEXPROCESSING : D3DCREATE_SOFTWARE_VERTEXPROCESSING, &pparams, &data->device); if (FAILED(result)) { D3D_DestroyRenderer(renderer); D3D_SetError("CreateDevice()", result); return NULL; } data->beginScene = SDL_TRUE; /* Get presentation parameters to fill info */ result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain); if (FAILED(result)) { D3D_DestroyRenderer(renderer); D3D_SetError("GetSwapChain()", result); return NULL; } result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams); if (FAILED(result)) { IDirect3DSwapChain9_Release(chain); D3D_DestroyRenderer(renderer); D3D_SetError("GetPresentParameters()", result); return NULL; } IDirect3DSwapChain9_Release(chain); if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) { renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; } data->pparams = pparams; D3D_AddTextureFormats(data, &renderer->info); IDirect3DDevice9_GetDeviceCaps(data->device, &caps); renderer->info.max_texture_width = caps.MaxTextureWidth; renderer->info.max_texture_height = caps.MaxTextureHeight; /* Set up parameters for rendering */ IDirect3DDevice9_SetVertexShader(data->device, NULL); IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); IDirect3DDevice9_SetRenderState(data->device, D3DRS_ZENABLE, D3DZB_FALSE); IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, D3DCULL_NONE); IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); /* Enable color modulation by diffuse color */ IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE); IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); /* Enable alpha modulation by diffuse alpha */ IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(data->device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE); /* Disable second texture stage, since we're done */ IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_COLOROP, D3DTOP_DISABLE); IDirect3DDevice9_SetTextureStageState(data->device, 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); return renderer; } static int D3D_Reset(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; HRESULT result; result = IDirect3DDevice9_Reset(data->device, &data->pparams); if (FAILED(result)) { if (result == D3DERR_DEVICELOST) { /* Don't worry about it, we'll reset later... */ return 0; } else { D3D_SetError("Reset()", result); return -1; } } IDirect3DDevice9_SetVertexShader(data->device, NULL); IDirect3DDevice9_SetFVF(data->device, D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); IDirect3DDevice9_SetRenderState(data->device, D3DRS_CULLMODE, D3DCULL_NONE); IDirect3DDevice9_SetRenderState(data->device, D3DRS_LIGHTING, FALSE); return 0; } /* FIXME: This needs to be called... when? */ #if 0 static int D3D_DisplayModeChanged(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; SDL_VideoDisplay *display = window->display; data->pparams.BackBufferWidth = window->w; data->pparams.BackBufferHeight = window->h; if (window->flags & SDL_WINDOW_FULLSCREEN) { data->pparams.BackBufferFormat = PixelFormatToD3DFMT(window->fullscreen_mode.format); } else { data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; } return D3D_Reset(renderer); } #endif static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) { D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; D3DFORMAT display_format = renderdata->pparams.BackBufferFormat; D3D_TextureData *data; HRESULT result; data = (D3D_TextureData *) SDL_calloc(1, sizeof(*data)); if (!data) { SDL_OutOfMemory(); return -1; } texture->driverdata = data; if (SDL_ISPIXELFORMAT_FOURCC(texture->format) && (texture->format != SDL_PIXELFORMAT_YUY2 || !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter, display_format, PixelFormatToD3DFMT(texture->format))) && (texture->format != SDL_PIXELFORMAT_YVYU || !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter, display_format, PixelFormatToD3DFMT(texture->format)))) { data->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h); if (!data->yuv) { return -1; } data->format = SDL_GetWindowPixelFormat(window); } else { data->format = texture->format; } result = IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, texture->h, 1, 0, PixelFormatToD3DFMT(data->format), D3DPOOL_SDL, &data->texture, NULL); if (FAILED(result)) { D3D_SetError("CreateTexture()", result); return -1; } return 0; } static int D3D_QueryTexturePixels(SDL_Renderer * renderer, SDL_Texture * texture, void **pixels, int *pitch) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; if (data->yuv) { return SDL_SW_QueryYUVTexturePixels(data->yuv, pixels, pitch); } else { /* D3D textures don't have their pixels hanging out */ return -1; } } 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; D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; if (data->yuv) { if (SDL_SW_UpdateYUVTexture(data->yuv, rect, pixels, pitch) < 0) { return -1; } UpdateYUVTextureData(texture); return 0; } else { #ifdef SDL_MEMORY_POOL_DEFAULT IDirect3DTexture9 *temp; RECT d3drect; D3DLOCKED_RECT locked; const Uint8 *src; Uint8 *dst; int row, length; HRESULT result; result = IDirect3DDevice9_CreateTexture(renderdata->device, texture->w, texture->h, 1, 0, PixelFormatToD3DFMT(texture-> format), D3DPOOL_SYSTEMMEM, &temp, NULL); if (FAILED(result)) { D3D_SetError("CreateTexture()", result); return -1; } d3drect.left = rect->x; d3drect.right = rect->x + rect->w; d3drect.top = rect->y; d3drect.bottom = rect->y + rect->h; result = IDirect3DTexture9_LockRect(temp, 0, &locked, &d3drect, 0); if (FAILED(result)) { IDirect3DTexture9_Release(temp); D3D_SetError("LockRect()", result); return -1; } src = pixels; dst = locked.pBits; length = rect->w * SDL_BYTESPERPIXEL(texture->format); for (row = 0; row < rect->h; ++row) { SDL_memcpy(dst, src, length); src += pitch; dst += locked.Pitch; } IDirect3DTexture9_UnlockRect(temp, 0); result = IDirect3DDevice9_UpdateTexture(renderdata->device, (IDirect3DBaseTexture9 *) temp, (IDirect3DBaseTexture9 *) data->texture); IDirect3DTexture9_Release(temp); if (FAILED(result)) { D3D_SetError("UpdateTexture()", result); return -1; } #else RECT d3drect; D3DLOCKED_RECT locked; const Uint8 *src; Uint8 *dst; int row, length; 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); if (FAILED(result)) { D3D_SetError("LockRect()", result); return -1; } src = pixels; dst = locked.pBits; length = rect->w * SDL_BYTESPERPIXEL(texture->format); for (row = 0; row < rect->h; ++row) { SDL_memcpy(dst, src, length); src += pitch; dst += locked.Pitch; } IDirect3DTexture9_UnlockRect(data->texture, 0); #endif // SDL_MEMORY_POOL_DEFAULT return 0; } } static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * rect, int markDirty, void **pixels, int *pitch) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; if (data->yuv) { return SDL_SW_LockYUVTexture(data->yuv, rect, markDirty, pixels, 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, markDirty ? 0 : D3DLOCK_NO_DIRTY_UPDATE); if (FAILED(result)) { D3D_SetError("LockRect()", result); return -1; } *pixels = locked.pBits; *pitch = locked.Pitch; return 0; } } static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; if (data->yuv) { SDL_SW_UnlockYUVTexture(data->yuv); UpdateYUVTextureData(texture); } else { IDirect3DTexture9_UnlockRect(data->texture, 0); } } static void D3D_DirtyTexture(SDL_Renderer * renderer, SDL_Texture * texture, int numrects, const SDL_Rect * rects) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; RECT d3drect; int i; for (i = 0; i < numrects; ++i) { const SDL_Rect *rect = &rects[i]; d3drect.left = rect->x; d3drect.right = rect->x + rect->w; d3drect.top = rect->y; d3drect.bottom = rect->y + rect->h; IDirect3DTexture9_AddDirtyRect(data->texture, &d3drect); } } static void D3D_SetBlendMode(D3D_RenderData * data, int blendMode) { switch (blendMode) { case SDL_BLENDMODE_NONE: IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE); break; case SDL_BLENDMODE_BLEND: IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE); IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); break; case SDL_BLENDMODE_ADD: IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE); IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, D3DBLEND_ONE); break; } } static int D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, int count) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; DWORD color; Vertex *vertices; int i; HRESULT result; if (data->beginScene) { IDirect3DDevice9_BeginScene(data->device); data->beginScene = SDL_FALSE; } D3D_SetBlendMode(data, renderer->blendMode); result = IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) 0); if (FAILED(result)) { D3D_SetError("SetTexture()", result); return -1; } color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); vertices = SDL_stack_alloc(Vertex, count); for (i = 0; i < count; ++i) { vertices[i].x = (float) points[i].x; vertices[i].y = (float) points[i].y; vertices[i].z = 0.0f; vertices[i].rhw = 1.0f; vertices[i].color = color; vertices[i].u = 0.0f; vertices[i].v = 0.0f; } result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count, vertices, sizeof(*vertices)); SDL_stack_free(vertices); if (FAILED(result)) { D3D_SetError("DrawPrimitiveUP()", result); return -1; } return 0; } static int D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, int count) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; DWORD color; Vertex *vertices; int i; HRESULT result; if (data->beginScene) { IDirect3DDevice9_BeginScene(data->device); data->beginScene = SDL_FALSE; } D3D_SetBlendMode(data, renderer->blendMode); result = IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) 0); if (FAILED(result)) { D3D_SetError("SetTexture()", result); return -1; } color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); vertices = SDL_stack_alloc(Vertex, count); for (i = 0; i < count; ++i) { vertices[i].x = (float) points[i].x; vertices[i].y = (float) points[i].y; vertices[i].z = 0.0f; vertices[i].rhw = 1.0f; vertices[i].color = color; vertices[i].u = 0.0f; vertices[i].v = 0.0f; } result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1, vertices, sizeof(*vertices)); /* DirectX 9 has the same line rasterization semantics as GDI, so we need to close the endpoint of the line */ if (points[0].x != points[count-1].x || points[0].y != points[count-1].y) { vertices[0].x = (float) points[count-1].x; vertices[0].y = (float) points[count-1].y; result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices)); } SDL_stack_free(vertices); if (FAILED(result)) { D3D_SetError("DrawPrimitiveUP()", result); return -1; } return 0; } static int D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; DWORD color; int i; float minx, miny, maxx, maxy; Vertex vertices[4]; HRESULT result; if (data->beginScene) { IDirect3DDevice9_BeginScene(data->device); data->beginScene = SDL_FALSE; } D3D_SetBlendMode(data, renderer->blendMode); result = IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) 0); if (FAILED(result)) { D3D_SetError("SetTexture()", result); return -1; } color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b); for (i = 0; i < count; ++i) { const SDL_Rect *rect = rects[i]; minx = (float) rect->x; miny = (float) rect->y; maxx = (float) rect->x + rect->w; maxy = (float) rect->y + rect->h; vertices[0].x = minx; vertices[0].y = miny; vertices[0].z = 0.0f; vertices[0].rhw = 1.0f; vertices[0].color = color; vertices[0].u = 0.0f; vertices[0].v = 0.0f; vertices[1].x = maxx; vertices[1].y = miny; vertices[1].z = 0.0f; vertices[1].rhw = 1.0f; vertices[1].color = color; vertices[1].u = 0.0f; vertices[1].v = 0.0f; vertices[2].x = maxx; vertices[2].y = maxy; vertices[2].z = 0.0f; vertices[2].rhw = 1.0f; vertices[2].color = color; vertices[2].u = 0.0f; vertices[2].v = 0.0f; vertices[3].x = minx; vertices[3].y = maxy; vertices[3].z = 0.0f; vertices[3].rhw = 1.0f; vertices[3].color = color; vertices[3].u = 0.0f; vertices[3].v = 0.0f; result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, vertices, sizeof(*vertices)); if (FAILED(result)) { D3D_SetError("DrawPrimitiveUP()", result); return -1; } } return 0; } static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, const SDL_Rect * srcrect, const SDL_Rect * dstrect) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata; LPDIRECT3DPIXELSHADER9 shader = NULL; float minx, miny, maxx, maxy; float minu, maxu, minv, maxv; DWORD color; Vertex vertices[4]; HRESULT result; if (data->beginScene) { IDirect3DDevice9_BeginScene(data->device); data->beginScene = SDL_FALSE; } minx = (float) dstrect->x - 0.5f; miny = (float) dstrect->y - 0.5f; maxx = (float) dstrect->x + dstrect->w - 0.5f; maxy = (float) dstrect->y + dstrect->h - 0.5f; minu = (float) srcrect->x / texture->w; maxu = (float) (srcrect->x + srcrect->w) / texture->w; minv = (float) srcrect->y / texture->h; maxv = (float) (srcrect->y + srcrect->h) / texture->h; color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); vertices[0].x = minx; vertices[0].y = miny; vertices[0].z = 0.0f; vertices[0].rhw = 1.0f; vertices[0].color = color; vertices[0].u = minu; vertices[0].v = minv; vertices[1].x = maxx; vertices[1].y = miny; vertices[1].z = 0.0f; vertices[1].rhw = 1.0f; vertices[1].color = color; vertices[1].u = maxu; vertices[1].v = minv; vertices[2].x = maxx; vertices[2].y = maxy; vertices[2].z = 0.0f; vertices[2].rhw = 1.0f; vertices[2].color = color; vertices[2].u = maxu; vertices[2].v = maxv; vertices[3].x = minx; vertices[3].y = maxy; vertices[3].z = 0.0f; vertices[3].rhw = 1.0f; vertices[3].color = color; vertices[3].u = minu; vertices[3].v = maxv; D3D_SetBlendMode(data, texture->blendMode); IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); result = IDirect3DDevice9_SetTexture(data->device, 0, (IDirect3DBaseTexture9 *) texturedata->texture); if (FAILED(result)) { D3D_SetError("SetTexture()", result); return -1; } if (shader) { result = IDirect3DDevice9_SetPixelShader(data->device, shader); if (FAILED(result)) { D3D_SetError("SetShader()", result); return -1; } } result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, vertices, sizeof(*vertices)); if (FAILED(result)) { D3D_SetError("DrawPrimitiveUP()", result); return -1; } if (shader) { result = IDirect3DDevice9_SetPixelShader(data->device, NULL); if (FAILED(result)) { D3D_SetError("SetShader()", result); return -1; } } return 0; } static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, void * pixels, int pitch) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; SDL_Window *window = renderer->window; SDL_VideoDisplay *display = window->display; D3DSURFACE_DESC desc; LPDIRECT3DSURFACE9 backBuffer; LPDIRECT3DSURFACE9 surface; RECT d3drect; D3DLOCKED_RECT locked; HRESULT result; result = IDirect3DDevice9_GetBackBuffer(data->device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); if (FAILED(result)) { D3D_SetError("GetBackBuffer()", result); return -1; } result = IDirect3DSurface9_GetDesc(backBuffer, &desc); if (FAILED(result)) { D3D_SetError("GetDesc()", result); IDirect3DSurface9_Release(backBuffer); return -1; } result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); if (FAILED(result)) { D3D_SetError("CreateOffscreenPlainSurface()", result); IDirect3DSurface9_Release(backBuffer); return -1; } result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface); if (FAILED(result)) { D3D_SetError("GetRenderTargetData()", result); IDirect3DSurface9_Release(surface); IDirect3DSurface9_Release(backBuffer); return -1; } d3drect.left = rect->x; d3drect.right = rect->x + rect->w; d3drect.top = rect->y; d3drect.bottom = rect->y + rect->h; result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY); if (FAILED(result)) { D3D_SetError("LockRect()", result); IDirect3DSurface9_Release(surface); IDirect3DSurface9_Release(backBuffer); return -1; } SDL_ConvertPixels(rect->w, rect->h, display->current_mode.format, locked.pBits, locked.Pitch, format, pixels, pitch); IDirect3DSurface9_UnlockRect(surface); IDirect3DSurface9_Release(surface); IDirect3DSurface9_Release(backBuffer); return 0; } static int D3D_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect, Uint32 format, const void * pixels, int pitch) { /* Work in progress */ SDL_Unsupported(); return -1; } static void D3D_RenderPresent(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; HRESULT result; if (!data->beginScene) { IDirect3DDevice9_EndScene(data->device); data->beginScene = SDL_TRUE; } result = IDirect3DDevice9_TestCooperativeLevel(data->device); if (result == D3DERR_DEVICELOST) { /* We'll reset later */ return; } if (result == D3DERR_DEVICENOTRESET) { D3D_Reset(renderer); } result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL); if (FAILED(result)) { D3D_SetError("Present()", result); } } static void D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) { D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; if (!data) { return; } if (data->yuv) { SDL_SW_DestroyYUVTexture(data->yuv); } if (data->texture) { IDirect3DTexture9_Release(data->texture); } SDL_free(data); texture->driverdata = NULL; } static void D3D_DestroyRenderer(SDL_Renderer * renderer) { D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; if (data) { if (data->device) { IDirect3DDevice9_Release(data->device); } if (data->d3d) { IDirect3D9_Release(data->d3d); SDL_UnloadObject(data->d3dDLL); } SDL_free(data); } SDL_free(renderer); } #endif /* SDL_VIDEO_RENDER_D3D */ /* vi: set ts=4 sw=4 expandtab: */