| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | #include <d3d9.h> |
| | | #endif |
| | | |
| | | |
| | | #ifdef ASSEMBLE_SHADER |
| | | #pragma comment(lib, "d3dx9.lib") |
| | | |
| | | /************************************************************************** |
| | | * 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); |
| | | |
| | | static void PrintShaderData(LPDWORD shader_data, DWORD shader_size) |
| | | { |
| | | OutputDebugStringA("const DWORD shader_data[] = {\n\t"); |
| | | { |
| | | SDL_bool newline = SDL_FALSE; |
| | | unsigned i; |
| | | for (i = 0; i < shader_size / sizeof(DWORD); ++i) { |
| | | char dword[11]; |
| | | if (i > 0) { |
| | | if ((i%6) == 0) { |
| | | newline = SDL_TRUE; |
| | | } |
| | | if (newline) { |
| | | OutputDebugStringA(",\n "); |
| | | newline = SDL_FALSE; |
| | | } else { |
| | | OutputDebugStringA(", "); |
| | | } |
| | | } |
| | | SDL_snprintf(dword, sizeof(dword), "0x%8.8x", shader_data[i]); |
| | | OutputDebugStringA(dword); |
| | | } |
| | | OutputDebugStringA("\n};\n"); |
| | | } |
| | | } |
| | | |
| | | #endif /* ASSEMBLE_SHADER */ |
| | | #include "SDL_shaders_d3d.h" |
| | | |
| | | |
| | | /* Direct3D renderer implementation */ |
| | |
| | | static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags); |
| | | static void D3D_WindowEvent(SDL_Renderer * renderer, |
| | | const SDL_WindowEvent *event); |
| | | static SDL_bool D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode); |
| | | 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, |
| | |
| | | IDirect3DSurface9 *defaultRenderTarget; |
| | | IDirect3DSurface9 *currentRenderTarget; |
| | | void* d3dxDLL; |
| | | LPDIRECT3DPIXELSHADER9 ps_yuv; |
| | | LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS]; |
| | | } D3D_RenderData; |
| | | |
| | | typedef struct |
| | |
| | | int w, h; |
| | | DWORD usage; |
| | | Uint32 format; |
| | | D3DFORMAT d3dfmt; |
| | | IDirect3DTexture9 *texture; |
| | | IDirect3DTexture9 *staging; |
| | | } D3D_TextureRep; |
| | |
| | | return D3DFMT_A8R8G8B8; |
| | | case SDL_PIXELFORMAT_YV12: |
| | | case SDL_PIXELFORMAT_IYUV: |
| | | case SDL_PIXELFORMAT_NV12: |
| | | case SDL_PIXELFORMAT_NV21: |
| | | return D3DFMT_L8; |
| | | default: |
| | | return D3DFMT_UNKNOWN; |
| | |
| | | } |
| | | |
| | | renderer->WindowEvent = D3D_WindowEvent; |
| | | renderer->SupportsBlendMode = D3D_SupportsBlendMode; |
| | | renderer->CreateTexture = D3D_CreateTexture; |
| | | renderer->UpdateTexture = D3D_UpdateTexture; |
| | | renderer->UpdateTextureYUV = D3D_UpdateTextureYUV; |
| | |
| | | /* Set up parameters for rendering */ |
| | | D3D_InitRenderState(data); |
| | | |
| | | if (caps.MaxSimultaneousTextures >= 3) |
| | | { |
| | | #ifdef ASSEMBLE_SHADER |
| | | /* This shader was created by running the following HLSL through the fxc compiler |
| | | and then tuning the generated assembly. |
| | | |
| | | fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx |
| | | |
| | | --- yuv.fx --- |
| | | Texture2D g_txY; |
| | | Texture2D g_txU; |
| | | Texture2D g_txV; |
| | | |
| | | SamplerState samLinear |
| | | { |
| | | Filter = ANISOTROPIC; |
| | | AddressU = Clamp; |
| | | AddressV = Clamp; |
| | | MaxAnisotropy = 1; |
| | | }; |
| | | |
| | | struct VS_OUTPUT |
| | | { |
| | | float2 TextureUV : TEXCOORD0; |
| | | }; |
| | | |
| | | struct PS_OUTPUT |
| | | { |
| | | float4 RGBAColor : SV_Target; |
| | | }; |
| | | |
| | | PS_OUTPUT YUV420( VS_OUTPUT In ) |
| | | { |
| | | const float3 offset = {-0.0627451017, -0.501960814, -0.501960814}; |
| | | const float3 Rcoeff = {1.164, 0.000, 1.596}; |
| | | const float3 Gcoeff = {1.164, -0.391, -0.813}; |
| | | const float3 Bcoeff = {1.164, 2.018, 0.000}; |
| | | |
| | | PS_OUTPUT Output; |
| | | float2 TextureUV = In.TextureUV; |
| | | |
| | | float3 yuv; |
| | | yuv.x = g_txY.Sample( samLinear, TextureUV ).r; |
| | | yuv.y = g_txU.Sample( samLinear, TextureUV ).r; |
| | | yuv.z = g_txV.Sample( samLinear, TextureUV ).r; |
| | | |
| | | yuv += offset; |
| | | Output.RGBAColor.r = dot(yuv, Rcoeff); |
| | | Output.RGBAColor.g = dot(yuv, Gcoeff); |
| | | Output.RGBAColor.b = dot(yuv, Bcoeff); |
| | | Output.RGBAColor.a = 1.0f; |
| | | |
| | | return Output; |
| | | } |
| | | |
| | | technique10 RenderYUV420 |
| | | { |
| | | pass P0 |
| | | { |
| | | SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) ); |
| | | } |
| | | } |
| | | */ |
| | | const char *shader_text = |
| | | "ps_2_0\n" |
| | | "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n" |
| | | "def c1, 1.16400003, 0, 1.59599996, 0\n" |
| | | "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n" |
| | | "def c3, 1.16400003, 2.01799989, 0, 0\n" |
| | | "dcl t0.xy\n" |
| | | "dcl v0.xyzw\n" |
| | | "dcl_2d s0\n" |
| | | "dcl_2d s1\n" |
| | | "dcl_2d s2\n" |
| | | "texld r0, t0, s0\n" |
| | | "texld r1, t0, s1\n" |
| | | "texld r2, t0, s2\n" |
| | | "mov r0.y, r1.x\n" |
| | | "mov r0.z, r2.x\n" |
| | | "add r0.xyz, r0, c0\n" |
| | | "dp3 r1.x, r0, c1\n" |
| | | "dp3 r1.y, r0, c2\n" |
| | | "dp2add r1.z, r0, c3, c3.z\n" /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */ |
| | | "mov r1.w, c0.w\n" |
| | | "mul r0, r1, v0\n" /* Not in the HLSL, multiply by vertex color */ |
| | | "mov oC0, r0\n" |
| | | ; |
| | | LPD3DXBUFFER pCode; |
| | | LPD3DXBUFFER pErrorMsgs; |
| | | LPDWORD shader_data = NULL; |
| | | DWORD shader_size = 0; |
| | | result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs); |
| | | if (!FAILED(result)) { |
| | | shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode); |
| | | shader_size = pCode->lpVtbl->GetBufferSize(pCode); |
| | | PrintShaderData(shader_data, shader_size); |
| | | } else { |
| | | const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs); |
| | | SDL_SetError("Couldn't assemble shader: %s", error); |
| | | } |
| | | #else |
| | | const DWORD shader_data[] = { |
| | | 0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081, |
| | | 0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba, |
| | | 0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5, |
| | | 0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000, |
| | | 0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000, |
| | | 0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000, |
| | | 0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000, |
| | | 0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801, |
| | | 0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000, |
| | | 0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000, |
| | | 0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001, |
| | | 0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001, |
| | | 0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000, |
| | | 0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800, |
| | | 0x80e40000, 0x0000ffff |
| | | }; |
| | | #endif |
| | | if (shader_data != NULL) { |
| | | result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv); |
| | | if (!FAILED(result)) { |
| | | renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; |
| | | renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; |
| | | } else { |
| | | if (caps.MaxSimultaneousTextures >= 3) { |
| | | int i; |
| | | for (i = 0; i < SDL_arraysize(data->shaders); ++i) { |
| | | result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]); |
| | | if (FAILED(result)) { |
| | | D3D_SetError("CreatePixelShader()", result); |
| | | } |
| | | } |
| | | if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) { |
| | | renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; |
| | | renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV; |
| | | } |
| | | } |
| | | |
| | | return renderer; |
| | | } |
| | | |
| | |
| | | if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { |
| | | data->updateSize = SDL_TRUE; |
| | | } |
| | | } |
| | | |
| | | static D3DBLEND GetBlendFunc(SDL_BlendFactor factor) |
| | | { |
| | | switch (factor) { |
| | | case SDL_BLENDFACTOR_ZERO: |
| | | return D3DBLEND_ZERO; |
| | | case SDL_BLENDFACTOR_ONE: |
| | | return D3DBLEND_ONE; |
| | | case SDL_BLENDFACTOR_SRC_COLOR: |
| | | return D3DBLEND_SRCCOLOR; |
| | | case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: |
| | | return D3DBLEND_INVSRCCOLOR; |
| | | case SDL_BLENDFACTOR_SRC_ALPHA: |
| | | return D3DBLEND_SRCALPHA; |
| | | case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: |
| | | return D3DBLEND_INVSRCALPHA; |
| | | case SDL_BLENDFACTOR_DST_COLOR: |
| | | return D3DBLEND_DESTCOLOR; |
| | | case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: |
| | | return D3DBLEND_INVDESTCOLOR; |
| | | case SDL_BLENDFACTOR_DST_ALPHA: |
| | | return D3DBLEND_DESTALPHA; |
| | | case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: |
| | | return D3DBLEND_INVDESTALPHA; |
| | | default: |
| | | return (D3DBLEND)0; |
| | | } |
| | | } |
| | | |
| | | static SDL_bool |
| | | D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) |
| | | { |
| | | D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; |
| | | SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); |
| | | SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); |
| | | SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); |
| | | SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); |
| | | SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); |
| | | SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); |
| | | |
| | | if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) || |
| | | !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) { |
| | | return SDL_FALSE; |
| | | } |
| | | if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) { |
| | | return SDL_FALSE; |
| | | } |
| | | if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) { |
| | | return SDL_FALSE; |
| | | } |
| | | return SDL_TRUE; |
| | | } |
| | | |
| | | static D3DTEXTUREFILTERTYPE |
| | |
| | | } |
| | | |
| | | static int |
| | | D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h) |
| | | D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h) |
| | | { |
| | | HRESULT result; |
| | | |
| | |
| | | texture->h = h; |
| | | texture->usage = usage; |
| | | texture->format = format; |
| | | texture->d3dfmt = d3dfmt; |
| | | |
| | | result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage, |
| | | PixelFormatToD3DFMT(format), |
| | |
| | | |
| | | if (texture->staging == NULL) { |
| | | result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0, |
| | | PixelFormatToD3DFMT(texture->format), |
| | | D3DPOOL_SYSTEMMEM, &texture->staging, NULL); |
| | | texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result); |
| | | } |
| | |
| | | } |
| | | |
| | | static int |
| | | D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h) |
| | | D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture) |
| | | { |
| | | if (texture->texture) { |
| | | IDirect3DTexture9_Release(texture->texture); |
| | |
| | | } |
| | | |
| | | static int |
| | | D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch) |
| | | D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch) |
| | | { |
| | | RECT d3drect; |
| | | D3DLOCKED_RECT locked; |
| | |
| | | } |
| | | |
| | | src = (const Uint8 *)pixels; |
| | | dst = locked.pBits; |
| | | length = w * SDL_BYTESPERPIXEL(format); |
| | | dst = (Uint8 *)locked.pBits; |
| | | length = w * SDL_BYTESPERPIXEL(texture->format); |
| | | if (length == pitch && length == locked.Pitch) { |
| | | SDL_memcpy(dst, src, length*h); |
| | | } else { |
| | |
| | | usage = 0; |
| | | } |
| | | |
| | | if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) { |
| | | if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | |
| | | 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) { |
| | | if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) { |
| | | if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | |
| | | return 0; |
| | | } |
| | | |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) { |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (texturedata->yuv) { |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) { |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) { |
| | | if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | |
| | | return -1; |
| | | } |
| | | |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) { |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | |
| | | /* Skip to the correct offset into the next texture */ |
| | | pixels = (const void*)((const Uint8*)pixels + rect->h * pitch); |
| | | |
| | | 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) { |
| | | if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 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_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) { |
| | | pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2)); |
| | | if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | |
| | | return -1; |
| | | } |
| | | |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { |
| | | return -1; |
| | | } |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) { |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch) < 0) { |
| | | return -1; |
| | | } |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) { |
| | | if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch) < 0) { |
| | | return -1; |
| | | } |
| | | return 0; |
| | |
| | | static int |
| | | D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) |
| | | { |
| | | D3D_ActivateRenderer(renderer); |
| | | if (D3D_ActivateRenderer(renderer) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | return D3D_SetRenderTargetInternal(renderer, texture); |
| | | } |
| | |
| | | } |
| | | |
| | | static void |
| | | D3D_SetBlendMode(D3D_RenderData * data, int blendMode) |
| | | D3D_SetBlendMode(D3D_RenderData * data, SDL_BlendMode 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); |
| | | if (blendMode == SDL_BLENDMODE_NONE) { |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE); |
| | | } else { |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE); |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, |
| | | D3DBLEND_SRCALPHA); |
| | | GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode))); |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, |
| | | D3DBLEND_INVSRCALPHA); |
| | | GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode))); |
| | | if (data->enableSeparateAlphaBlend) { |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, |
| | | D3DBLEND_ONE); |
| | | GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode))); |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, |
| | | D3DBLEND_INVSRCALPHA); |
| | | GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode))); |
| | | } |
| | | 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); |
| | | if (data->enableSeparateAlphaBlend) { |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, |
| | | D3DBLEND_ZERO); |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, |
| | | 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); |
| | | if (data->enableSeparateAlphaBlend) { |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, |
| | | D3DBLEND_ZERO); |
| | | IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, |
| | | D3DBLEND_ONE); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | |
| | |
| | | texturedata->scaleMode); |
| | | IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, |
| | | texturedata->scaleMode); |
| | | IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, |
| | | D3DTADDRESS_CLAMP); |
| | | IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, |
| | | D3DTADDRESS_CLAMP); |
| | | data->scaleMode[index] = texturedata->scaleMode; |
| | | } |
| | | } |
| | | |
| | | static int |
| | | D3D_RenderSetupTextureState(SDL_Renderer * renderer, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader) |
| | | { |
| | | D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; |
| | | D3D_TextureData *texturedata; |
| | | |
| | | *shader = NULL; |
| | | |
| | | texturedata = (D3D_TextureData *)texture->driverdata; |
| | | if (!texturedata) { |
| | | SDL_SetError("Texture is not currently available"); |
| | | return -1; |
| | | } |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 0); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (texturedata->yuv) { |
| | | switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { |
| | | case SDL_YUV_CONVERSION_JPEG: |
| | | *shader = data->shaders[SHADER_YUV_JPEG]; |
| | | break; |
| | | case SDL_YUV_CONVERSION_BT601: |
| | | *shader = data->shaders[SHADER_YUV_BT601]; |
| | | break; |
| | | case SDL_YUV_CONVERSION_BT709: |
| | | *shader = data->shaders[SHADER_YUV_BT709]; |
| | | break; |
| | | default: |
| | | return SDL_SetError("Unsupported YUV conversion mode"); |
| | | } |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 1); |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 2); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { |
| | | return -1; |
| | | } |
| | | if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | |
| | | const SDL_Rect * srcrect, const SDL_FRect * dstrect) |
| | | { |
| | | D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; |
| | | D3D_TextureData *texturedata; |
| | | LPDIRECT3DPIXELSHADER9 shader = NULL; |
| | | LPDIRECT3DPIXELSHADER9 shader; |
| | | float minx, miny, maxx, maxy; |
| | | float minu, maxu, minv, maxv; |
| | | DWORD color; |
| | |
| | | HRESULT result; |
| | | |
| | | if (D3D_ActivateRenderer(renderer) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | texturedata = (D3D_TextureData *)texture->driverdata; |
| | | if (!texturedata) { |
| | | SDL_SetError("Texture is not currently available"); |
| | | return -1; |
| | | } |
| | | |
| | |
| | | |
| | | D3D_SetBlendMode(data, texture->blendMode); |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 0); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) { |
| | | if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (texturedata->yuv) { |
| | | shader = data->ps_yuv; |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 1); |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 2); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { |
| | | return -1; |
| | | } |
| | | if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | if (shader) { |
| | | result = IDirect3DDevice9_SetPixelShader(data->device, shader); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("SetShader()", result); |
| | | } |
| | | } |
| | | result = |
| | | IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, |
| | | vertices, sizeof(*vertices)); |
| | | result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, |
| | | vertices, sizeof(*vertices)); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("DrawPrimitiveUP()", result); |
| | | D3D_SetError("DrawPrimitiveUP()", result); |
| | | } |
| | | if (shader) { |
| | | result = IDirect3DDevice9_SetPixelShader(data->device, NULL); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("SetShader()", result); |
| | | } |
| | | IDirect3DDevice9_SetPixelShader(data->device, NULL); |
| | | } |
| | | return 0; |
| | | return FAILED(result) ? -1 : 0; |
| | | } |
| | | |
| | | |
| | |
| | | const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) |
| | | { |
| | | D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; |
| | | D3D_TextureData *texturedata; |
| | | LPDIRECT3DPIXELSHADER9 shader = NULL; |
| | | float minx, miny, maxx, maxy; |
| | | float minu, maxu, minv, maxv; |
| | |
| | | return -1; |
| | | } |
| | | |
| | | texturedata = (D3D_TextureData *)texture->driverdata; |
| | | if (!texturedata) { |
| | | SDL_SetError("Texture is not currently available"); |
| | | return -1; |
| | | } |
| | | |
| | | centerx = center->x; |
| | | centery = center->y; |
| | | |
| | | if (flip & SDL_FLIP_HORIZONTAL) { |
| | | minx = dstrect->w - centerx - 0.5f; |
| | | maxx = -centerx - 0.5f; |
| | | } |
| | | else { |
| | | minx = -centerx - 0.5f; |
| | | maxx = dstrect->w - centerx - 0.5f; |
| | | } |
| | | |
| | | if (flip & SDL_FLIP_VERTICAL) { |
| | | miny = dstrect->h - centery - 0.5f; |
| | | maxy = -centery - 0.5f; |
| | | } |
| | | else { |
| | | miny = -centery - 0.5f; |
| | | maxy = dstrect->h - centery - 0.5f; |
| | | } |
| | | minx = -centerx; |
| | | maxx = dstrect->w - centerx; |
| | | miny = -centery; |
| | | maxy = dstrect->h - centery; |
| | | |
| | | 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; |
| | | |
| | | if (flip & SDL_FLIP_HORIZONTAL) { |
| | | float tmp = maxu; |
| | | maxu = minu; |
| | | minu = tmp; |
| | | } |
| | | if (flip & SDL_FLIP_VERTICAL) { |
| | | float tmp = maxv; |
| | | maxv = minv; |
| | | minv = tmp; |
| | | } |
| | | |
| | | color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b); |
| | | |
| | |
| | | |
| | | D3D_SetBlendMode(data, texture->blendMode); |
| | | |
| | | /* Rotate and translate */ |
| | | modelMatrix = MatrixMultiply( |
| | | MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)), |
| | | MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0) |
| | | ); |
| | | IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix); |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 0); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) { |
| | | if (D3D_RenderSetupTextureState(renderer, texture, &shader) < 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (texturedata->yuv) { |
| | | shader = data->ps_yuv; |
| | | |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 1); |
| | | D3D_UpdateTextureScaleMode(data, texturedata, 2); |
| | | |
| | | if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) { |
| | | return -1; |
| | | } |
| | | if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | /* Rotate and translate */ |
| | | modelMatrix = MatrixMultiply( |
| | | MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)), |
| | | MatrixTranslation(dstrect->x + center->x - 0.5f, dstrect->y + center->y - 0.5f, 0)); |
| | | IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix); |
| | | |
| | | if (shader) { |
| | | result = IDirect3DDevice9_SetPixelShader(data->device, shader); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("SetShader()", result); |
| | | D3D_SetError("SetShader()", result); |
| | | goto done; |
| | | } |
| | | } |
| | | result = |
| | | IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, |
| | | vertices, sizeof(*vertices)); |
| | | result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, |
| | | vertices, sizeof(*vertices)); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("DrawPrimitiveUP()", result); |
| | | D3D_SetError("DrawPrimitiveUP()", result); |
| | | } |
| | | done: |
| | | if (shader) { |
| | | result = IDirect3DDevice9_SetPixelShader(data->device, NULL); |
| | | if (FAILED(result)) { |
| | | return D3D_SetError("SetShader()", result); |
| | | } |
| | | IDirect3DDevice9_SetPixelShader(data->device, NULL); |
| | | } |
| | | |
| | | modelMatrix = MatrixIdentity(); |
| | | IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix); |
| | | return 0; |
| | | |
| | | return FAILED(result) ? -1 : 0; |
| | | } |
| | | |
| | | static int |
| | |
| | | D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata; |
| | | |
| | | if (data) { |
| | | int i; |
| | | |
| | | /* Release the render target */ |
| | | if (data->defaultRenderTarget) { |
| | | IDirect3DSurface9_Release(data->defaultRenderTarget); |
| | |
| | | IDirect3DSurface9_Release(data->currentRenderTarget); |
| | | data->currentRenderTarget = NULL; |
| | | } |
| | | if (data->ps_yuv) { |
| | | IDirect3DPixelShader9_Release(data->ps_yuv); |
| | | for (i = 0; i < SDL_arraysize(data->shaders); ++i) { |
| | | if (data->shaders[i]) { |
| | | IDirect3DPixelShader9_Release(data->shaders[i]); |
| | | data->shaders[i] = NULL; |
| | | } |
| | | } |
| | | if (data->device) { |
| | | IDirect3DDevice9_Release(data->device); |
| | | data->device = NULL; |
| | | } |
| | | if (data->d3d) { |
| | | IDirect3D9_Release(data->d3d); |