Mercurial > sdl-ios-xcode
diff src/video/windows/SDL_d3drender.c @ 5062:e8916fe9cfc8
Fixed bug #925
Changed "win32" to "windows"
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 20 Jan 2011 18:04:05 -0800 |
parents | src/video/win32/SDL_d3drender.c@aa8888658021 |
children | da10636e5eca |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/video/windows/SDL_d3drender.c Thu Jan 20 18:04:05 2011 -0800 @@ -0,0 +1,1533 @@ +/* + 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 "SDL_windowsvideo.h" +#include "../SDL_yuv_sw_c.h" + +#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_DisplayModeChanged(SDL_Renderer * renderer); +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_SetTexturePalette(SDL_Renderer * renderer, + SDL_Texture * texture, + const SDL_Color * colors, int firstcolor, + int ncolors); +static int D3D_GetTexturePalette(SDL_Renderer * renderer, + SDL_Texture * texture, SDL_Color * colors, + int firstcolor, int ncolors); +static int D3D_SetTextureColorMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int D3D_SetTextureAlphaMod(SDL_Renderer * renderer, + SDL_Texture * texture); +static int D3D_SetTextureBlendMode(SDL_Renderer * renderer, + SDL_Texture * texture); +static int D3D_SetTextureScaleMode(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); +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_RenderDrawRects(SDL_Renderer * renderer, + const SDL_Rect ** rects, 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_SINGLEBUFFER | SDL_RENDERER_PRESENTCOPY | + SDL_RENDERER_PRESENTFLIP2 | SDL_RENDERER_PRESENTFLIP3 | + SDL_RENDERER_PRESENTDISCARD | SDL_RENDERER_PRESENTVSYNC | + SDL_RENDERER_ACCELERATED), + (SDL_TEXTUREMODULATE_NONE | SDL_TEXTUREMODULATE_COLOR | + SDL_TEXTUREMODULATE_ALPHA), + (SDL_BLENDMODE_NONE | SDL_BLENDMODE_MASK | + SDL_BLENDMODE_BLEND | SDL_BLENDMODE_ADD | SDL_BLENDMODE_MOD), + (SDL_SCALEMODE_NONE | SDL_SCALEMODE_FAST | + SDL_SCALEMODE_SLOW | SDL_SCALEMODE_BEST), + 0, + {0}, + 0, + 0} +}; + +typedef struct +{ + IDirect3D9 *d3d; + IDirect3DDevice9 *device; + UINT adapter; + D3DPRESENT_PARAMETERS pparams; + LPDIRECT3DPIXELSHADER9 ps_mask; + 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 UINT D3D_FindAdapter(IDirect3D9 * d3d, SDL_VideoDisplay * display) +{ + SDL_DisplayData *displaydata = (SDL_DisplayData *) display->driverdata; + UINT adapter, count; + + count = IDirect3D9_GetAdapterCount(d3d); + for (adapter = 0; adapter < count; ++adapter) { + HRESULT result; + D3DADAPTER_IDENTIFIER9 info; + char *name; + + result = IDirect3D9_GetAdapterIdentifier(d3d, adapter, 0, &info); + if (FAILED(result)) { + continue; + } + name = WIN_StringToUTF8(displaydata->DeviceName); + if (SDL_strcmp(name, info.DeviceName) == 0) { + SDL_free(name); + return adapter; + } + SDL_free(name); + } + + /* This should never happen, but just in case... */ + return D3DADAPTER_DEFAULT; +} + +static SDL_bool +D3D_IsTextureFormatAvailable(IDirect3D9 * d3d, UINT adapter, + Uint32 display_format, + Uint32 texture_format) +{ + HRESULT result; + + result = IDirect3D9_CheckDeviceFormat(d3d, adapter, + D3DDEVTYPE_HAL, + PixelFormatToD3DFMT(display_format), + 0, + D3DRTYPE_TEXTURE, + PixelFormatToD3DFMT + (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); +} + +void +D3D_AddRenderDriver(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + SDL_RendererInfo *info = &D3D_RenderDriver.info; + + if (data->d3d) { + int i, j; + int formats[] = { + SDL_PIXELFORMAT_INDEX8, + 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, + }; + + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + SDL_DisplayMode *mode = &display->desktop_mode; + UINT adapter = D3D_FindAdapter(data->d3d, display); + + /* Get the matching D3D adapter for this display */ + info->num_texture_formats = 0; + for (j = 0; j < SDL_arraysize(formats); ++j) { + if (D3D_IsTextureFormatAvailable + (data->d3d, adapter, mode->format, formats[j])) { + info->texture_formats[info->num_texture_formats++] = + formats[j]; + } + } + 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_AddRenderDriver(display, &D3D_RenderDriver); + } + } +} + +SDL_Renderer * +D3D_CreateRenderer(SDL_Window * window, Uint32 flags) +{ + SDL_VideoDisplay *display = window->display; + SDL_VideoData *videodata = (SDL_VideoData *) display->device->driverdata; + SDL_WindowData *windowdata = (SDL_WindowData *) window->driverdata; + SDL_Renderer *renderer; + D3D_RenderData *data; + 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) { + D3D_DestroyRenderer(renderer); + SDL_OutOfMemory(); + return NULL; + } + data->d3d = videodata->d3d; + + videodata->render = RENDER_D3D; + + renderer->DisplayModeChanged = D3D_DisplayModeChanged; + renderer->CreateTexture = D3D_CreateTexture; + renderer->QueryTexturePixels = D3D_QueryTexturePixels; + renderer->SetTexturePalette = D3D_SetTexturePalette; + renderer->GetTexturePalette = D3D_GetTexturePalette; + renderer->SetTextureColorMod = D3D_SetTextureColorMod; + renderer->SetTextureAlphaMod = D3D_SetTextureAlphaMod; + renderer->SetTextureBlendMode = D3D_SetTextureBlendMode; + renderer->SetTextureScaleMode = D3D_SetTextureScaleMode; + 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->RenderDrawRects = D3D_RenderDrawRects; + 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_zero(pparams); + 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; + } + if (flags & SDL_RENDERER_PRESENTFLIP2) { + pparams.BackBufferCount = 2; + pparams.SwapEffect = D3DSWAPEFFECT_FLIP; + } else if (flags & SDL_RENDERER_PRESENTFLIP3) { + pparams.BackBufferCount = 3; + pparams.SwapEffect = D3DSWAPEFFECT_FLIP; + } else if (flags & SDL_RENDERER_PRESENTCOPY) { + pparams.BackBufferCount = 1; + pparams.SwapEffect = D3DSWAPEFFECT_COPY; + } else { + 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; + } + + data->adapter = D3D_FindAdapter(videodata->d3d, display); + IDirect3D9_GetDeviceCaps(videodata->d3d, data->adapter, + D3DDEVTYPE_HAL, &caps); + + result = IDirect3D9_CreateDevice(videodata->d3d, data->adapter, + D3DDEVTYPE_HAL, + windowdata->hwnd, + (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); + switch (pparams.SwapEffect) { + case D3DSWAPEFFECT_COPY: + renderer->info.flags |= SDL_RENDERER_PRESENTCOPY; + break; + case D3DSWAPEFFECT_FLIP: + switch (pparams.BackBufferCount) { + case 2: + renderer->info.flags |= SDL_RENDERER_PRESENTFLIP2; + break; + case 3: + renderer->info.flags |= SDL_RENDERER_PRESENTFLIP3; + break; + } + break; + case D3DSWAPEFFECT_DISCARD: + renderer->info.flags |= SDL_RENDERER_PRESENTDISCARD; + break; + } + if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) { + renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC; + } + data->pparams = pparams; + + 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); + + { +#ifdef ASSEMBLE_SHADER + const char *shader_text = +"ps_1_1\n" +"def c0, 0, 0, 0, 0.496\n" +"def c1, 0, 0, 0, 1\n" +"def c2, 0, 0, 0, -1\n" +"tex t0\n" +"mul r1, t0, v0\n" +"add r0, r1, c0\n" +"cnd r0, r0.a, c1, c2\n" +"add r0, r0, r1\n"; + LPD3DXBUFFER pCode; // buffer with the assembled shader code + LPD3DXBUFFER pErrorMsgs; // buffer with error messages + LPDWORD shader_data; + DWORD shader_size; + result = D3DXAssembleShader( shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs ); + if (FAILED(result)) { + D3D_SetError("D3DXAssembleShader()", result); + } + shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode); + shader_size = pCode->lpVtbl->GetBufferSize(pCode); +#else + const DWORD shader_data[] = { + 0xffff0101,0x00000051,0xa00f0000,0x00000000,0x00000000,0x00000000, + 0x3efdf3b6,0x00000051,0xa00f0001,0x00000000,0x00000000,0x00000000, + 0x3f800000,0x00000051,0xa00f0002,0x00000000,0x00000000,0x00000000, + 0xbf800000,0x00000042,0xb00f0000,0x00000005,0x800f0001,0xb0e40000, + 0x90e40000,0x00000002,0x800f0000,0x80e40001,0xa0e40000,0x00000050, + 0x800f0000,0x80ff0000,0xa0e40001,0xa0e40002,0x00000002,0x800f0000, + 0x80e40000,0x80e40001,0x0000ffff + }; +#endif + result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_mask); + if (FAILED(result)) { + D3D_SetError("CreatePixelShader()", result); + } + } + + 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; +} + +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); +} + +static int +D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; + SDL_Window *window = renderer->window; + SDL_VideoDisplay *display = window->display; + Uint32 display_format = display->current_mode.format; + 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, texture->format)) + && (texture->format != SDL_PIXELFORMAT_YVYU + || !D3D_IsTextureFormatAvailable(renderdata->d3d, renderdata->adapter, + display_format, texture->format))) { + data->yuv = + SDL_SW_CreateYUVTexture(texture->format, texture->w, texture->h); + if (!data->yuv) { + return -1; + } + data->format = display->current_mode.format; + } 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_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Color * colors, int firstcolor, int ncolors) +{ + D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata; + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + + return 0; +} + +static int +D3D_GetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, + SDL_Color * colors, int firstcolor, int ncolors) +{ + D3D_TextureData *data = (D3D_TextureData *) texture->driverdata; + + return 0; +} + +static int +D3D_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + return 0; +} + +static int +D3D_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) +{ + return 0; +} + +static int +D3D_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) +{ + switch (texture->blendMode) { + case SDL_BLENDMODE_NONE: + case SDL_BLENDMODE_MASK: + case SDL_BLENDMODE_BLEND: + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_MOD: + return 0; + default: + SDL_Unsupported(); + texture->blendMode = SDL_BLENDMODE_NONE; + return -1; + } +} + +static int +D3D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture) +{ + switch (texture->scaleMode) { + case SDL_SCALEMODE_NONE: + case SDL_SCALEMODE_FAST: + case SDL_SCALEMODE_SLOW: + case SDL_SCALEMODE_BEST: + return 0; + default: + SDL_Unsupported(); + texture->scaleMode = SDL_SCALEMODE_NONE; + 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; + 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_MASK: + 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; + case SDL_BLENDMODE_MOD: + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, + TRUE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, + D3DBLEND_ZERO); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, + D3DBLEND_SRCCOLOR); + 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_RenderDrawRects(SDL_Renderer * renderer, const SDL_Rect ** rects, + int count) +{ + D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; + DWORD color; + int i; + Vertex vertices[5]; + 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 < SDL_arraysize(vertices); ++i) { + vertices[i].z = 0.0f; + vertices[i].rhw = 1.0f; + vertices[i].color = color; + vertices[i].u = 0.0f; + vertices[i].v = 0.0f; + } + + for (i = 0; i < count; ++i) { + const SDL_Rect *rect = rects[i]; + + vertices[0].x = (float) rect->x; + vertices[0].y = (float) rect->y; + + vertices[1].x = (float) rect->x+rect->w-1; + vertices[1].y = (float) rect->y; + + vertices[2].x = (float) rect->x+rect->w-1; + vertices[2].y = (float) rect->y+rect->h-1; + + vertices[3].x = (float) rect->x; + vertices[3].y = (float) rect->y+rect->h-1; + + vertices[4].x = (float) rect->x; + vertices[4].y = (float) rect->y; + + result = + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, 4, + vertices, sizeof(*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); + + if (texture->blendMode == SDL_BLENDMODE_MASK) { + shader = data->ps_mask; + } + + switch (texture->scaleMode) { + case SDL_SCALEMODE_NONE: + case SDL_SCALEMODE_FAST: + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, + D3DTEXF_POINT); + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, + D3DTEXF_POINT); + break; + case SDL_SCALEMODE_SLOW: + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, + D3DTEXF_LINEAR); + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, + D3DTEXF_LINEAR); + break; + case SDL_SCALEMODE_BEST: + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MINFILTER, + D3DTEXF_GAUSSIANQUAD); + IDirect3DDevice9_SetSamplerState(data->device, 0, D3DSAMP_MAGFILTER, + D3DTEXF_GAUSSIANQUAD); + break; + } + + 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); + } + SDL_free(data); + } + SDL_free(renderer); +} + +#endif /* SDL_VIDEO_RENDER_D3D */ + +/* vi: set ts=4 sw=4 expandtab: */