From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/render/SDL_d3dmath.c | 135 + contrib/SDL-3.2.8/src/render/SDL_d3dmath.h | 85 + contrib/SDL-3.2.8/src/render/SDL_render.c | 5676 ++++++++++++++++++++ .../SDL-3.2.8/src/render/SDL_render_debug_font.h | 2331 ++++++++ .../SDL-3.2.8/src/render/SDL_render_unsupported.c | 22 + contrib/SDL-3.2.8/src/render/SDL_sysrender.h | 372 ++ contrib/SDL-3.2.8/src/render/SDL_yuv_sw.c | 404 ++ contrib/SDL-3.2.8/src/render/SDL_yuv_sw_c.h | 63 + .../src/render/direct3d/D3D9_PixelShader_YUV.h | 164 + .../src/render/direct3d/D3D9_PixelShader_YUV.hlsl | 47 + .../SDL-3.2.8/src/render/direct3d/SDL_render_d3d.c | 1778 ++++++ .../src/render/direct3d/SDL_shaders_d3d.c | 48 + .../src/render/direct3d/SDL_shaders_d3d.h | 32 + .../src/render/direct3d/compile_shaders.bat | 1 + .../render/direct3d11/D3D11_PixelShader_Advanced.h | 1060 ++++ .../direct3d11/D3D11_PixelShader_Advanced.hlsl | 7 + .../render/direct3d11/D3D11_PixelShader_Colors.h | 284 + .../direct3d11/D3D11_PixelShader_Colors.hlsl | 7 + .../direct3d11/D3D11_PixelShader_Common.hlsli | 235 + .../render/direct3d11/D3D11_PixelShader_Textures.h | 332 ++ .../direct3d11/D3D11_PixelShader_Textures.hlsl | 9 + .../src/render/direct3d11/D3D11_VertexShader.h | 339 ++ .../src/render/direct3d11/D3D11_VertexShader.hlsl | 38 + .../src/render/direct3d11/SDL_render_d3d11.c | 2767 ++++++++++ .../src/render/direct3d11/SDL_shaders_d3d11.c | 116 + .../src/render/direct3d11/SDL_shaders_d3d11.h | 35 + .../src/render/direct3d11/compile_shaders.bat | 4 + .../render/direct3d12/D3D12_PixelShader_Advanced.h | 1389 +++++ .../direct3d12/D3D12_PixelShader_Advanced.hlsl | 8 + .../render/direct3d12/D3D12_PixelShader_Colors.h | 490 ++ .../direct3d12/D3D12_PixelShader_Colors.hlsl | 8 + .../direct3d12/D3D12_PixelShader_Common.hlsli | 236 + .../render/direct3d12/D3D12_PixelShader_Textures.h | 586 ++ .../direct3d12/D3D12_PixelShader_Textures.hlsl | 8 + .../src/render/direct3d12/D3D12_RootSig_Advanced.h | 31 + .../src/render/direct3d12/D3D12_RootSig_Color.h | 16 + .../src/render/direct3d12/D3D12_RootSig_Texture.h | 23 + .../render/direct3d12/D3D12_Shader_Common.hlsli | 37 + .../src/render/direct3d12/D3D12_VertexShader.hlsl | 45 + .../direct3d12/D3D12_VertexShader_Advanced.h | 653 +++ .../render/direct3d12/D3D12_VertexShader_Color.h | 637 +++ .../render/direct3d12/D3D12_VertexShader_Texture.h | 645 +++ .../src/render/direct3d12/SDL_render_d3d12.c | 3309 ++++++++++++ .../render/direct3d12/SDL_render_d3d12_xbox.cpp | 174 + .../src/render/direct3d12/SDL_render_d3d12_xbox.h | 44 + .../src/render/direct3d12/SDL_shaders_d3d12.c | 125 + .../src/render/direct3d12/SDL_shaders_d3d12.h | 54 + .../direct3d12/SDL_shaders_d3d12_xboxone.cpp | 132 + .../direct3d12/SDL_shaders_d3d12_xboxseries.cpp | 133 + .../src/render/direct3d12/compile_shaders.bat | 21 + .../src/render/direct3d12/compile_shaders_xbox.bat | 13 + contrib/SDL-3.2.8/src/render/gpu/SDL_gpu_util.h | 74 + .../SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c | 202 + .../SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.h | 47 + contrib/SDL-3.2.8/src/render/gpu/SDL_render_gpu.c | 1276 +++++ contrib/SDL-3.2.8/src/render/gpu/SDL_shaders_gpu.c | 232 + contrib/SDL-3.2.8/src/render/gpu/SDL_shaders_gpu.h | 63 + .../src/render/gpu/shaders/.gitattributes | 1 + .../SDL-3.2.8/src/render/gpu/shaders/.gitignore | 4 + .../src/render/gpu/shaders/build-shaders.sh | 106 + .../SDL-3.2.8/src/render/gpu/shaders/color.frag | 9 + .../src/render/gpu/shaders/color.frag.metal.h | 28 + .../src/render/gpu/shaders/color.frag.sm50.dxbc.h | 85 + .../src/render/gpu/shaders/color.frag.sm60.dxil.h | 340 ++ .../src/render/gpu/shaders/color.frag.spv.h | 29 + contrib/SDL-3.2.8/src/render/gpu/shaders/dxbc50.h | 6 + contrib/SDL-3.2.8/src/render/gpu/shaders/dxil60.h | 6 + .../src/render/gpu/shaders/linepoint.vert | 17 + .../src/render/gpu/shaders/linepoint.vert.metal.h | 51 + .../render/gpu/shaders/linepoint.vert.sm50.dxbc.h | 172 + .../render/gpu/shaders/linepoint.vert.sm60.dxil.h | 496 ++ .../src/render/gpu/shaders/linepoint.vert.spv.h | 93 + contrib/SDL-3.2.8/src/render/gpu/shaders/metal.h | 6 + contrib/SDL-3.2.8/src/render/gpu/shaders/spir-v.h | 6 + .../src/render/gpu/shaders/texture_rgb.frag | 12 + .../render/gpu/shaders/texture_rgb.frag.metal.h | 41 + .../gpu/shaders/texture_rgb.frag.sm50.dxbc.h | 123 + .../gpu/shaders/texture_rgb.frag.sm60.dxil.h | 465 ++ .../src/render/gpu/shaders/texture_rgb.frag.spv.h | 59 + .../src/render/gpu/shaders/texture_rgba.frag | 12 + .../render/gpu/shaders/texture_rgba.frag.metal.h | 40 + .../gpu/shaders/texture_rgba.frag.sm50.dxbc.h | 120 + .../gpu/shaders/texture_rgba.frag.sm60.dxil.h | 467 ++ .../src/render/gpu/shaders/texture_rgba.frag.spv.h | 50 + .../src/render/gpu/shaders/tri_color.vert | 17 + .../src/render/gpu/shaders/tri_color.vert.metal.h | 48 + .../render/gpu/shaders/tri_color.vert.sm50.dxbc.h | 178 + .../render/gpu/shaders/tri_color.vert.sm60.dxil.h | 515 ++ .../src/render/gpu/shaders/tri_color.vert.spv.h | 89 + .../src/render/gpu/shaders/tri_texture.vert | 20 + .../render/gpu/shaders/tri_texture.vert.metal.h | 56 + .../gpu/shaders/tri_texture.vert.sm50.dxbc.h | 195 + .../gpu/shaders/tri_texture.vert.sm60.dxil.h | 558 ++ .../src/render/gpu/shaders/tri_texture.vert.spv.h | 106 + .../SDL-3.2.8/src/render/metal/SDL_render_metal.m | 2196 ++++++++ .../src/render/metal/SDL_shaders_metal.metal | 299 ++ .../src/render/metal/SDL_shaders_metal_ios.h | 2612 +++++++++ .../metal/SDL_shaders_metal_iphonesimulator.h | 3155 +++++++++++ .../src/render/metal/SDL_shaders_metal_macos.h | 2532 +++++++++ .../src/render/metal/SDL_shaders_metal_tvos.h | 2612 +++++++++ .../render/metal/SDL_shaders_metal_tvsimulator.h | 3155 +++++++++++ .../src/render/metal/build-metal-shaders.sh | 24 + contrib/SDL-3.2.8/src/render/opengl/SDL_glfuncs.h | 476 ++ .../SDL-3.2.8/src/render/opengl/SDL_render_gl.c | 1844 +++++++ .../SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c | 545 ++ .../SDL-3.2.8/src/render/opengl/SDL_shaders_gl.h | 52 + .../src/render/opengles2/SDL_gles2funcs.h | 78 + .../src/render/opengles2/SDL_render_gles2.c | 2226 ++++++++ .../src/render/opengles2/SDL_shaders_gles2.c | 387 ++ .../src/render/opengles2/SDL_shaders_gles2.h | 65 + contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c | 727 +++ contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c | 1400 +++++ .../SDL-3.2.8/src/render/psp/SDL_render_psp_c.h | 30 + .../src/render/software/SDL_blendfillrect.c | 371 ++ .../src/render/software/SDL_blendfillrect.h | 30 + .../SDL-3.2.8/src/render/software/SDL_blendline.c | 986 ++++ .../SDL-3.2.8/src/render/software/SDL_blendline.h | 30 + .../SDL-3.2.8/src/render/software/SDL_blendpoint.c | 376 ++ .../SDL-3.2.8/src/render/software/SDL_blendpoint.h | 30 + contrib/SDL-3.2.8/src/render/software/SDL_draw.h | 723 +++ .../SDL-3.2.8/src/render/software/SDL_drawline.c | 199 + .../SDL-3.2.8/src/render/software/SDL_drawline.h | 30 + .../SDL-3.2.8/src/render/software/SDL_drawpoint.c | 108 + .../SDL-3.2.8/src/render/software/SDL_drawpoint.h | 30 + .../SDL-3.2.8/src/render/software/SDL_render_sw.c | 1202 +++++ .../src/render/software/SDL_render_sw_c.h | 27 + contrib/SDL-3.2.8/src/render/software/SDL_rotate.c | 612 +++ contrib/SDL-3.2.8/src/render/software/SDL_rotate.h | 30 + .../SDL-3.2.8/src/render/software/SDL_triangle.c | 945 ++++ .../SDL-3.2.8/src/render/software/SDL_triangle.h | 42 + .../src/render/vitagxm/SDL_render_vita_gxm.c | 1198 +++++ .../render/vitagxm/SDL_render_vita_gxm_memory.c | 179 + .../render/vitagxm/SDL_render_vita_gxm_memory.h | 42 + .../render/vitagxm/SDL_render_vita_gxm_shaders.h | 282 + .../src/render/vitagxm/SDL_render_vita_gxm_tools.c | 1213 +++++ .../src/render/vitagxm/SDL_render_vita_gxm_tools.h | 63 + .../src/render/vitagxm/SDL_render_vita_gxm_types.h | 210 + .../src/render/vitagxm/shader_src/clear_f.cg | 4 + .../src/render/vitagxm/shader_src/clear_v.cg | 4 + .../src/render/vitagxm/shader_src/color_f.cg | 4 + .../src/render/vitagxm/shader_src/color_v.cg | 13 + .../src/render/vitagxm/shader_src/texture_f.cg | 4 + .../src/render/vitagxm/shader_src/texture_v.cg | 14 + .../src/render/vulkan/SDL_render_vulkan.c | 4349 +++++++++++++++ .../src/render/vulkan/SDL_shaders_vulkan.c | 60 + .../src/render/vulkan/SDL_shaders_vulkan.h | 44 + .../render/vulkan/VULKAN_PixelShader_Advanced.h | 271 + .../render/vulkan/VULKAN_PixelShader_Advanced.hlsl | 7 + .../src/render/vulkan/VULKAN_PixelShader_Colors.h | 41 + .../render/vulkan/VULKAN_PixelShader_Colors.hlsl | 7 + .../render/vulkan/VULKAN_PixelShader_Common.hlsli | 181 + .../render/vulkan/VULKAN_PixelShader_Textures.h | 50 + .../render/vulkan/VULKAN_PixelShader_Textures.hlsl | 7 + .../src/render/vulkan/VULKAN_VertexShader.h | 51 + .../src/render/vulkan/VULKAN_VertexShader.hlsl | 45 + .../src/render/vulkan/compile_shaders.bat | 5 + 156 files changed, 70262 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/render/SDL_d3dmath.c create mode 100644 contrib/SDL-3.2.8/src/render/SDL_d3dmath.h create mode 100644 contrib/SDL-3.2.8/src/render/SDL_render.c create mode 100644 contrib/SDL-3.2.8/src/render/SDL_render_debug_font.h create mode 100644 contrib/SDL-3.2.8/src/render/SDL_render_unsupported.c create mode 100644 contrib/SDL-3.2.8/src/render/SDL_sysrender.h create mode 100644 contrib/SDL-3.2.8/src/render/SDL_yuv_sw.c create mode 100644 contrib/SDL-3.2.8/src/render/SDL_yuv_sw_c.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/SDL_render_d3d.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d/compile_shaders.bat create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Common.hlsli create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/SDL_render_d3d11.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d11/compile_shaders.bat create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Advanced.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Advanced.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Colors.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Colors.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Common.hlsli create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Textures.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Textures.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_RootSig_Advanced.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_RootSig_Color.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_RootSig_Texture.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_Shader_Common.hlsli create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_VertexShader.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_VertexShader_Advanced.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_VertexShader_Color.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/D3D12_VertexShader_Texture.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_render_d3d12.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_render_d3d12_xbox.cpp create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_render_d3d12_xbox.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_shaders_d3d12.c create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_shaders_d3d12.h create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_shaders_d3d12_xboxone.cpp create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/SDL_shaders_d3d12_xboxseries.cpp create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/compile_shaders.bat create mode 100644 contrib/SDL-3.2.8/src/render/direct3d12/compile_shaders_xbox.bat create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_gpu_util.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.c create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_pipeline_gpu.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_render_gpu.c create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_shaders_gpu.c create mode 100644 contrib/SDL-3.2.8/src/render/gpu/SDL_shaders_gpu.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/.gitattributes create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/.gitignore create mode 100755 contrib/SDL-3.2.8/src/render/gpu/shaders/build-shaders.sh create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/color.frag create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/color.frag.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/color.frag.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/color.frag.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/color.frag.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/dxbc50.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/dxil60.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/linepoint.vert create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/linepoint.vert.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/linepoint.vert.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/linepoint.vert.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/linepoint.vert.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/spir-v.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgb.frag create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgb.frag.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgb.frag.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgb.frag.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgb.frag.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgba.frag create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgba.frag.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgba.frag.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgba.frag.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/texture_rgba.frag.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_color.vert create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_color.vert.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_color.vert.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_color.vert.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_color.vert.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_texture.vert create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_texture.vert.metal.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_texture.vert.sm50.dxbc.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_texture.vert.sm60.dxil.h create mode 100644 contrib/SDL-3.2.8/src/render/gpu/shaders/tri_texture.vert.spv.h create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_render_metal.m create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal.metal create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal_ios.h create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal_iphonesimulator.h create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal_macos.h create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal_tvos.h create mode 100644 contrib/SDL-3.2.8/src/render/metal/SDL_shaders_metal_tvsimulator.h create mode 100755 contrib/SDL-3.2.8/src/render/metal/build-metal-shaders.sh create mode 100644 contrib/SDL-3.2.8/src/render/opengl/SDL_glfuncs.h create mode 100644 contrib/SDL-3.2.8/src/render/opengl/SDL_render_gl.c create mode 100644 contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.c create mode 100644 contrib/SDL-3.2.8/src/render/opengl/SDL_shaders_gl.h create mode 100644 contrib/SDL-3.2.8/src/render/opengles2/SDL_gles2funcs.h create mode 100644 contrib/SDL-3.2.8/src/render/opengles2/SDL_render_gles2.c create mode 100644 contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.c create mode 100644 contrib/SDL-3.2.8/src/render/opengles2/SDL_shaders_gles2.h create mode 100644 contrib/SDL-3.2.8/src/render/ps2/SDL_render_ps2.c create mode 100644 contrib/SDL-3.2.8/src/render/psp/SDL_render_psp.c create mode 100644 contrib/SDL-3.2.8/src/render/psp/SDL_render_psp_c.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendfillrect.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendline.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendline.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_blendpoint.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_draw.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawline.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawline.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_drawpoint.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_render_sw.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_render_sw_c.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_rotate.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_rotate.h create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_triangle.c create mode 100644 contrib/SDL-3.2.8/src/render/software/SDL_triangle.h create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm.c create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_memory.c create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_memory.h create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_shaders.h create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_tools.c create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_tools.h create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/SDL_render_vita_gxm_types.h create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/clear_f.cg create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/clear_v.cg create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/color_f.cg create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/color_v.cg create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/texture_f.cg create mode 100644 contrib/SDL-3.2.8/src/render/vitagxm/shader_src/texture_v.cg create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/SDL_render_vulkan.c create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/SDL_shaders_vulkan.c create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/SDL_shaders_vulkan.h create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Advanced.h create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Advanced.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Colors.h create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Colors.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Common.hlsli create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Textures.h create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_PixelShader_Textures.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_VertexShader.h create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/VULKAN_VertexShader.hlsl create mode 100644 contrib/SDL-3.2.8/src/render/vulkan/compile_shaders.bat (limited to 'contrib/SDL-3.2.8/src/render') diff --git a/contrib/SDL-3.2.8/src/render/SDL_d3dmath.c b/contrib/SDL-3.2.8/src/render/SDL_d3dmath.c new file mode 100644 index 0000000..6a1ab59 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_d3dmath.c @@ -0,0 +1,135 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_RENDER_D3D) || \ + defined(SDL_VIDEO_RENDER_D3D11) || \ + defined(SDL_VIDEO_RENDER_D3D12) || \ + defined(SDL_VIDEO_RENDER_VULKAN) + +#include "SDL_d3dmath.h" + +// Direct3D matrix math functions + +Float4X4 MatrixIdentity(void) +{ + Float4X4 m; + SDL_zero(m); + m.v._11 = 1.0f; + m.v._22 = 1.0f; + m.v._33 = 1.0f; + m.v._44 = 1.0f; + return m; +} + +Float4X4 MatrixMultiply(Float4X4 M1, Float4X4 M2) +{ + Float4X4 m; + m.v._11 = M1.v._11 * M2.v._11 + M1.v._12 * M2.v._21 + M1.v._13 * M2.v._31 + M1.v._14 * M2.v._41; + m.v._12 = M1.v._11 * M2.v._12 + M1.v._12 * M2.v._22 + M1.v._13 * M2.v._32 + M1.v._14 * M2.v._42; + m.v._13 = M1.v._11 * M2.v._13 + M1.v._12 * M2.v._23 + M1.v._13 * M2.v._33 + M1.v._14 * M2.v._43; + m.v._14 = M1.v._11 * M2.v._14 + M1.v._12 * M2.v._24 + M1.v._13 * M2.v._34 + M1.v._14 * M2.v._44; + m.v._21 = M1.v._21 * M2.v._11 + M1.v._22 * M2.v._21 + M1.v._23 * M2.v._31 + M1.v._24 * M2.v._41; + m.v._22 = M1.v._21 * M2.v._12 + M1.v._22 * M2.v._22 + M1.v._23 * M2.v._32 + M1.v._24 * M2.v._42; + m.v._23 = M1.v._21 * M2.v._13 + M1.v._22 * M2.v._23 + M1.v._23 * M2.v._33 + M1.v._24 * M2.v._43; + m.v._24 = M1.v._21 * M2.v._14 + M1.v._22 * M2.v._24 + M1.v._23 * M2.v._34 + M1.v._24 * M2.v._44; + m.v._31 = M1.v._31 * M2.v._11 + M1.v._32 * M2.v._21 + M1.v._33 * M2.v._31 + M1.v._34 * M2.v._41; + m.v._32 = M1.v._31 * M2.v._12 + M1.v._32 * M2.v._22 + M1.v._33 * M2.v._32 + M1.v._34 * M2.v._42; + m.v._33 = M1.v._31 * M2.v._13 + M1.v._32 * M2.v._23 + M1.v._33 * M2.v._33 + M1.v._34 * M2.v._43; + m.v._34 = M1.v._31 * M2.v._14 + M1.v._32 * M2.v._24 + M1.v._33 * M2.v._34 + M1.v._34 * M2.v._44; + m.v._41 = M1.v._41 * M2.v._11 + M1.v._42 * M2.v._21 + M1.v._43 * M2.v._31 + M1.v._44 * M2.v._41; + m.v._42 = M1.v._41 * M2.v._12 + M1.v._42 * M2.v._22 + M1.v._43 * M2.v._32 + M1.v._44 * M2.v._42; + m.v._43 = M1.v._41 * M2.v._13 + M1.v._42 * M2.v._23 + M1.v._43 * M2.v._33 + M1.v._44 * M2.v._43; + m.v._44 = M1.v._41 * M2.v._14 + M1.v._42 * M2.v._24 + M1.v._43 * M2.v._34 + M1.v._44 * M2.v._44; + return m; +} + +Float4X4 MatrixScaling(float x, float y, float z) +{ + Float4X4 m; + SDL_zero(m); + m.v._11 = x; + m.v._22 = y; + m.v._33 = z; + m.v._44 = 1.0f; + return m; +} + +Float4X4 MatrixTranslation(float x, float y, float z) +{ + Float4X4 m; + SDL_zero(m); + m.v._11 = 1.0f; + m.v._22 = 1.0f; + m.v._33 = 1.0f; + m.v._44 = 1.0f; + m.v._41 = x; + m.v._42 = y; + m.v._43 = z; + return m; +} + +Float4X4 MatrixRotationX(float r) +{ + float sinR = SDL_sinf(r); + float cosR = SDL_cosf(r); + Float4X4 m; + SDL_zero(m); + m.v._11 = 1.0f; + m.v._22 = cosR; + m.v._23 = sinR; + m.v._32 = -sinR; + m.v._33 = cosR; + m.v._44 = 1.0f; + return m; +} + +Float4X4 MatrixRotationY(float r) +{ + float sinR = SDL_sinf(r); + float cosR = SDL_cosf(r); + Float4X4 m; + SDL_zero(m); + m.v._11 = cosR; + m.v._13 = -sinR; + m.v._22 = 1.0f; + m.v._31 = sinR; + m.v._33 = cosR; + m.v._44 = 1.0f; + return m; +} + +Float4X4 MatrixRotationZ(float r) +{ + float sinR = SDL_sinf(r); + float cosR = SDL_cosf(r); + Float4X4 m; + SDL_zero(m); + m.v._11 = cosR; + m.v._12 = sinR; + m.v._21 = -sinR; + m.v._22 = cosR; + m.v._33 = 1.0f; + m.v._44 = 1.0f; + return m; +} + +#endif // SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12 || SDL_VIDEO_RENDER_VULKAN diff --git a/contrib/SDL-3.2.8/src/render/SDL_d3dmath.h b/contrib/SDL-3.2.8/src/render/SDL_d3dmath.h new file mode 100644 index 0000000..84cff9e --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_d3dmath.h @@ -0,0 +1,85 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_VIDEO_RENDER_D3D) || \ + defined(SDL_VIDEO_RENDER_D3D11) || \ + defined(SDL_VIDEO_RENDER_D3D12) || \ + defined(SDL_VIDEO_RENDER_GPU) || \ + defined(SDL_VIDEO_RENDER_VULKAN) + +// Set up for C function definitions, even when using C++ +#ifdef __cplusplus +extern "C" { +#endif + +// Direct3D matrix math functions + +typedef struct +{ + float x; + float y; +} Float2; + +typedef struct +{ + float x; + float y; + float z; +} Float3; + +typedef struct +{ + float x; + float y; + float z; + float w; +} Float4; + +typedef struct +{ + union + { + struct + { + float _11, _12, _13, _14; + float _21, _22, _23, _24; + float _31, _32, _33, _34; + float _41, _42, _43, _44; + } v; + float m[4][4]; + }; +} Float4X4; + +extern Float4X4 MatrixIdentity(void); +extern Float4X4 MatrixMultiply(Float4X4 M1, Float4X4 M2); +extern Float4X4 MatrixScaling(float x, float y, float z); +extern Float4X4 MatrixTranslation(float x, float y, float z); +extern Float4X4 MatrixRotationX(float r); +extern Float4X4 MatrixRotationY(float r); +extern Float4X4 MatrixRotationZ(float r); + +// Ends C function definitions when using C++ +#ifdef __cplusplus +} +#endif + +#endif // SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12 || SDL_VIDEO_RENDER_VULKAN diff --git a/contrib/SDL-3.2.8/src/render/SDL_render.c b/contrib/SDL-3.2.8/src/render/SDL_render.c new file mode 100644 index 0000000..82ecb88 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_render.c @@ -0,0 +1,5676 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// The SDL 2D rendering system + +#include "SDL_sysrender.h" +#include "SDL_render_debug_font.h" +#include "software/SDL_render_sw_c.h" +#include "../events/SDL_windowevents_c.h" +#include "../video/SDL_pixels_c.h" +#include "../video/SDL_video_c.h" + +#ifdef SDL_PLATFORM_ANDROID +#include "../core/android/SDL_android.h" +#include "../video/android/SDL_androidevents.h" +#endif + +/* as a courtesy to iOS apps, we don't try to draw when in the background, as +that will crash the app. However, these apps _should_ have used +SDL_AddEventWatch to catch SDL_EVENT_WILL_ENTER_BACKGROUND events and stopped +drawing themselves. Other platforms still draw, as the compositor can use it, +and more importantly: drawing to render targets isn't lost. But I still think +this should probably be removed at some point in the future. --ryan. */ +#if defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) || defined(SDL_PLATFORM_ANDROID) +#define DONT_DRAW_WHILE_HIDDEN 1 +#else +#define DONT_DRAW_WHILE_HIDDEN 0 +#endif + +#define SDL_PROP_WINDOW_RENDERER_POINTER "SDL.internal.window.renderer" +#define SDL_PROP_TEXTURE_PARENT_POINTER "SDL.internal.texture.parent" + +#define CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result) \ + if (!SDL_ObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER)) { \ + SDL_InvalidParamError("renderer"); \ + return result; \ + } + +#define CHECK_RENDERER_MAGIC(renderer, result) \ + CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer, result); \ + if ((renderer)->destroyed) { \ + SDL_SetError("Renderer's window has been destroyed, can't use further"); \ + return result; \ + } + +#define CHECK_TEXTURE_MAGIC(texture, result) \ + if (!SDL_ObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE)) { \ + SDL_InvalidParamError("texture"); \ + return result; \ + } + +// Predefined blend modes +#define SDL_COMPOSE_BLENDMODE(srcColorFactor, dstColorFactor, colorOperation, \ + srcAlphaFactor, dstAlphaFactor, alphaOperation) \ + (SDL_BlendMode)(((Uint32)(colorOperation) << 0) | \ + ((Uint32)(srcColorFactor) << 4) | \ + ((Uint32)(dstColorFactor) << 8) | \ + ((Uint32)(alphaOperation) << 16) | \ + ((Uint32)(srcAlphaFactor) << 20) | \ + ((Uint32)(dstAlphaFactor) << 24)) + +#define SDL_BLENDMODE_NONE_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_BLEND_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_BLEND_PREMULTIPLIED_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_ADD_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_ADD_PREMULTIPLIED_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_MOD_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) + +#define SDL_BLENDMODE_MUL_FULL \ + SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_DST_COLOR, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, \ + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) + +#ifndef SDL_RENDER_DISABLED +static const SDL_RenderDriver *render_drivers[] = { +#ifdef SDL_VIDEO_RENDER_D3D11 + &D3D11_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_D3D12 + &D3D12_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_D3D + &D3D_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_METAL + &METAL_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_OGL + &GL_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_OGL_ES2 + &GLES2_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_PS2 + &PS2_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_PSP + &PSP_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_VITA_GXM + &VITA_GXM_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_VULKAN + &VULKAN_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_GPU + &GPU_RenderDriver, +#endif +#ifdef SDL_VIDEO_RENDER_SW + &SW_RenderDriver, +#endif + NULL +}; +#endif // !SDL_RENDER_DISABLED + +static SDL_Renderer *SDL_renderers; + +static const int rect_index_order[] = { 0, 1, 2, 0, 2, 3 }; + +void SDL_QuitRender(void) +{ + while (SDL_renderers) { + SDL_DestroyRenderer(SDL_renderers); + } +} + +bool SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelFormat format) +{ + SDL_PixelFormat *texture_formats = (SDL_PixelFormat *)SDL_realloc((void *)renderer->texture_formats, (renderer->num_texture_formats + 2) * sizeof(SDL_PixelFormat)); + if (!texture_formats) { + return false; + } + texture_formats[renderer->num_texture_formats++] = format; + texture_formats[renderer->num_texture_formats] = SDL_PIXELFORMAT_UNKNOWN; + renderer->texture_formats = texture_formats; + SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, texture_formats); + return true; +} + +void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props) +{ + renderer->output_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB); +} + +bool SDL_RenderingLinearSpace(SDL_Renderer *renderer) +{ + SDL_Colorspace colorspace; + + if (renderer->target) { + colorspace = renderer->target->colorspace; + } else { + colorspace = renderer->output_colorspace; + } + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return true; + } + return false; +} + +void SDL_ConvertToLinear(SDL_FColor *color) +{ + color->r = SDL_sRGBtoLinear(color->r); + color->g = SDL_sRGBtoLinear(color->g); + color->b = SDL_sRGBtoLinear(color->b); +} + +void SDL_ConvertFromLinear(SDL_FColor *color) +{ + color->r = SDL_sRGBfromLinear(color->r); + color->g = SDL_sRGBfromLinear(color->g); + color->b = SDL_sRGBfromLinear(color->b); +} + +static SDL_INLINE void DebugLogRenderCommands(const SDL_RenderCommand *cmd) +{ +#if 0 + unsigned int i = 1; + SDL_Log("Render commands to flush:"); + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_NO_OP: + SDL_Log(" %u. no-op", i++); + break; + + case SDL_RENDERCMD_SETVIEWPORT: + SDL_Log(" %u. set viewport (first=%u, rect={(%d, %d), %dx%d})", i++, + (unsigned int) cmd->data.viewport.first, + cmd->data.viewport.rect.x, cmd->data.viewport.rect.y, + cmd->data.viewport.rect.w, cmd->data.viewport.rect.h); + break; + + case SDL_RENDERCMD_SETCLIPRECT: + SDL_Log(" %u. set cliprect (enabled=%s, rect={(%d, %d), %dx%d})", i++, + cmd->data.cliprect.enabled ? "true" : "false", + cmd->data.cliprect.rect.x, cmd->data.cliprect.rect.y, + cmd->data.cliprect.rect.w, cmd->data.cliprect.rect.h); + break; + + case SDL_RENDERCMD_SETDRAWCOLOR: + SDL_Log(" %u. set draw color (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, + (unsigned int) cmd->data.color.first, + (int) cmd->data.color.color.r, (int) cmd->data.color.color.g, + (int) cmd->data.color.color.b, (int) cmd->data.color.color.a, cmd->data.color.color_scale); + break; + + case SDL_RENDERCMD_CLEAR: + SDL_Log(" %u. clear (first=%u, r=%d, g=%d, b=%d, a=%d, color_scale=%g)", i++, + (unsigned int) cmd->data.color.first, + (int) cmd->data.color.color.r, (int) cmd->data.color.color.g, + (int) cmd->data.color.color.b, (int) cmd->data.color.color.a, cmd->data.color.color_scale); + break; + + case SDL_RENDERCMD_DRAW_POINTS: + SDL_Log(" %u. draw points (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale); + break; + + case SDL_RENDERCMD_DRAW_LINES: + SDL_Log(" %u. draw lines (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale); + break; + + case SDL_RENDERCMD_FILL_RECTS: + SDL_Log(" %u. fill rects (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale); + break; + + case SDL_RENDERCMD_COPY: + SDL_Log(" %u. copy (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; + + + case SDL_RENDERCMD_COPY_EX: + SDL_Log(" %u. copyex (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; + + case SDL_RENDERCMD_GEOMETRY: + SDL_Log(" %u. geometry (first=%u, count=%u, r=%d, g=%d, b=%d, a=%d, blend=%d, color_scale=%g, tex=%p)", i++, + (unsigned int) cmd->data.draw.first, + (unsigned int) cmd->data.draw.count, + (int) cmd->data.draw.color.r, (int) cmd->data.draw.color.g, + (int) cmd->data.draw.color.b, (int) cmd->data.draw.color.a, + (int) cmd->data.draw.blend, cmd->data.draw.color_scale, cmd->data.draw.texture); + break; + + } + cmd = cmd->next; + } +#endif +} + +static bool FlushRenderCommands(SDL_Renderer *renderer) +{ + bool result; + + SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL)); + + if (!renderer->render_commands) { // nothing to do! + SDL_assert(renderer->vertex_data_used == 0); + return true; + } + + DebugLogRenderCommands(renderer->render_commands); + + result = renderer->RunCommandQueue(renderer, renderer->render_commands, renderer->vertex_data, renderer->vertex_data_used); + + // Move the whole render command queue to the unused pool so we can reuse them next time. + if (renderer->render_commands_tail) { + renderer->render_commands_tail->next = renderer->render_commands_pool; + renderer->render_commands_pool = renderer->render_commands; + renderer->render_commands_tail = NULL; + renderer->render_commands = NULL; + } + renderer->vertex_data_used = 0; + renderer->render_command_generation++; + renderer->color_queued = false; + renderer->viewport_queued = false; + renderer->cliprect_queued = false; + return result; +} + +static bool FlushRenderCommandsIfTextureNeeded(SDL_Texture *texture) +{ + SDL_Renderer *renderer = texture->renderer; + if (texture->last_command_generation == renderer->render_command_generation) { + // the current command queue depends on this texture, flush the queue now before it changes + return FlushRenderCommands(renderer); + } + return true; +} + +bool SDL_FlushRenderer(SDL_Renderer *renderer) +{ + if (!FlushRenderCommands(renderer)) { + return false; + } + renderer->InvalidateCachedState(renderer); + return true; +} + +void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, size_t numbytes, size_t alignment, size_t *offset) +{ + const size_t needed = renderer->vertex_data_used + numbytes + alignment; + const size_t current_offset = renderer->vertex_data_used; + + const size_t aligner = (alignment && ((current_offset & (alignment - 1)) != 0)) ? (alignment - (current_offset & (alignment - 1))) : 0; + const size_t aligned = current_offset + aligner; + + if (renderer->vertex_data_allocation < needed) { + const size_t current_allocation = renderer->vertex_data ? renderer->vertex_data_allocation : 1024; + size_t newsize = current_allocation * 2; + void *ptr; + while (newsize < needed) { + newsize *= 2; + } + + ptr = SDL_realloc(renderer->vertex_data, newsize); + + if (!ptr) { + return NULL; + } + renderer->vertex_data = ptr; + renderer->vertex_data_allocation = newsize; + } + + if (offset) { + *offset = aligned; + } + + renderer->vertex_data_used += aligner + numbytes; + + return ((Uint8 *)renderer->vertex_data) + aligned; +} + +static SDL_RenderCommand *AllocateRenderCommand(SDL_Renderer *renderer) +{ + SDL_RenderCommand *result = NULL; + + result = renderer->render_commands_pool; + if (result) { + renderer->render_commands_pool = result->next; + result->next = NULL; + } else { + result = (SDL_RenderCommand *)SDL_calloc(1, sizeof(*result)); + if (!result) { + return NULL; + } + } + + SDL_assert((renderer->render_commands == NULL) == (renderer->render_commands_tail == NULL)); + if (renderer->render_commands_tail) { + renderer->render_commands_tail->next = result; + } else { + renderer->render_commands = result; + } + renderer->render_commands_tail = result; + + return result; +} + +static void UpdatePixelViewport(SDL_Renderer *renderer, SDL_RenderViewState *view) +{ + view->pixel_viewport.x = (int)SDL_floorf((view->viewport.x * view->current_scale.x) + view->logical_offset.x); + view->pixel_viewport.y = (int)SDL_floorf((view->viewport.y * view->current_scale.y) + view->logical_offset.y); + if (view->viewport.w >= 0) { + view->pixel_viewport.w = (int)SDL_ceilf(view->viewport.w * view->current_scale.x); + } else { + view->pixel_viewport.w = view->pixel_w; + } + if (view->viewport.h >= 0) { + view->pixel_viewport.h = (int)SDL_ceilf(view->viewport.h * view->current_scale.y); + } else { + view->pixel_viewport.h = view->pixel_h; + } +} + +static bool QueueCmdSetViewport(SDL_Renderer *renderer) +{ + bool result = true; + + SDL_Rect viewport = renderer->view->pixel_viewport; + + if (!renderer->viewport_queued || + SDL_memcmp(&viewport, &renderer->last_queued_viewport, sizeof(viewport)) != 0) { + SDL_RenderCommand *cmd = AllocateRenderCommand(renderer); + if (cmd) { + cmd->command = SDL_RENDERCMD_SETVIEWPORT; + cmd->data.viewport.first = 0; // render backend will fill this in. + SDL_copyp(&cmd->data.viewport.rect, &viewport); + result = renderer->QueueSetViewport(renderer, cmd); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } else { + SDL_copyp(&renderer->last_queued_viewport, &viewport); + renderer->viewport_queued = true; + } + } else { + result = false; + } + } + return result; +} + +static void UpdatePixelClipRect(SDL_Renderer *renderer, SDL_RenderViewState *view) +{ + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + view->pixel_clip_rect.x = (int)SDL_floorf(view->clip_rect.x * scale_x); + view->pixel_clip_rect.y = (int)SDL_floorf(view->clip_rect.y * scale_y); + view->pixel_clip_rect.w = (int)SDL_ceilf(view->clip_rect.w * scale_x); + view->pixel_clip_rect.h = (int)SDL_ceilf(view->clip_rect.h * scale_y); +} + +static bool QueueCmdSetClipRect(SDL_Renderer *renderer) +{ + bool result = true; + + const SDL_RenderViewState *view = renderer->view; + SDL_Rect clip_rect = view->pixel_clip_rect; + if (!renderer->cliprect_queued || + view->clipping_enabled != renderer->last_queued_cliprect_enabled || + SDL_memcmp(&clip_rect, &renderer->last_queued_cliprect, sizeof(clip_rect)) != 0) { + SDL_RenderCommand *cmd = AllocateRenderCommand(renderer); + if (cmd) { + cmd->command = SDL_RENDERCMD_SETCLIPRECT; + cmd->data.cliprect.enabled = view->clipping_enabled; + SDL_copyp(&cmd->data.cliprect.rect, &clip_rect); + SDL_copyp(&renderer->last_queued_cliprect, &clip_rect); + renderer->last_queued_cliprect_enabled = view->clipping_enabled; + renderer->cliprect_queued = true; + } else { + result = false; + } + } + return result; +} + +static bool QueueCmdSetDrawColor(SDL_Renderer *renderer, SDL_FColor *color) +{ + bool result = true; + + if (!renderer->color_queued || + color->r != renderer->last_queued_color.r || + color->g != renderer->last_queued_color.g || + color->b != renderer->last_queued_color.b || + color->a != renderer->last_queued_color.a) { + SDL_RenderCommand *cmd = AllocateRenderCommand(renderer); + result = false; + + if (cmd) { + cmd->command = SDL_RENDERCMD_SETDRAWCOLOR; + cmd->data.color.first = 0; // render backend will fill this in. + cmd->data.color.color_scale = renderer->color_scale; + cmd->data.color.color = *color; + result = renderer->QueueSetDrawColor(renderer, cmd); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } else { + renderer->last_queued_color = *color; + renderer->color_queued = true; + } + } + } + return result; +} + +static bool QueueCmdClear(SDL_Renderer *renderer) +{ + SDL_RenderCommand *cmd = AllocateRenderCommand(renderer); + if (!cmd) { + return false; + } + + cmd->command = SDL_RENDERCMD_CLEAR; + cmd->data.color.first = 0; + cmd->data.color.color_scale = renderer->color_scale; + cmd->data.color.color = renderer->color; + return true; +} + +static SDL_RenderCommand *PrepQueueCmdDraw(SDL_Renderer *renderer, const SDL_RenderCommandType cmdtype, SDL_Texture *texture) +{ + SDL_RenderCommand *cmd = NULL; + bool result = true; + SDL_FColor *color; + SDL_BlendMode blendMode; + + if (texture) { + color = &texture->color; + blendMode = texture->blendMode; + } else { + color = &renderer->color; + blendMode = renderer->blendMode; + } + + if (cmdtype != SDL_RENDERCMD_GEOMETRY) { + result = QueueCmdSetDrawColor(renderer, color); + } + + /* Set the viewport and clip rect directly before draws, so the backends + * don't have to worry about that state not being valid at draw time. */ + if (result && !renderer->viewport_queued) { + result = QueueCmdSetViewport(renderer); + } + if (result && !renderer->cliprect_queued) { + result = QueueCmdSetClipRect(renderer); + } + + if (result) { + cmd = AllocateRenderCommand(renderer); + if (cmd) { + cmd->command = cmdtype; + cmd->data.draw.first = 0; // render backend will fill this in. + cmd->data.draw.count = 0; // render backend will fill this in. + cmd->data.draw.color_scale = renderer->color_scale; + cmd->data.draw.color = *color; + cmd->data.draw.blend = blendMode; + cmd->data.draw.texture = texture; + cmd->data.draw.texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; + } + } + return cmd; +} + +static bool QueueCmdDrawPoints(SDL_Renderer *renderer, const SDL_FPoint *points, const int count) +{ + SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_DRAW_POINTS, NULL); + bool result = false; + if (cmd) { + result = renderer->QueueDrawPoints(renderer, cmd, points, count); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + return result; +} + +static bool QueueCmdDrawLines(SDL_Renderer *renderer, const SDL_FPoint *points, const int count) +{ + SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_DRAW_LINES, NULL); + bool result = false; + if (cmd) { + result = renderer->QueueDrawLines(renderer, cmd, points, count); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + return result; +} + +static bool QueueCmdFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, const int count) +{ + SDL_RenderCommand *cmd; + bool result = false; + const int use_rendergeometry = (!renderer->QueueFillRects); + + cmd = PrepQueueCmdDraw(renderer, (use_rendergeometry ? SDL_RENDERCMD_GEOMETRY : SDL_RENDERCMD_FILL_RECTS), NULL); + + if (cmd) { + if (use_rendergeometry) { + bool isstack1; + bool isstack2; + float *xy = SDL_small_alloc(float, 4 * 2 * count, &isstack1); + int *indices = SDL_small_alloc(int, 6 * count, &isstack2); + + if (xy && indices) { + int i; + float *ptr_xy = xy; + int *ptr_indices = indices; + const int xy_stride = 2 * sizeof(float); + const int num_vertices = 4 * count; + const int num_indices = 6 * count; + const int size_indices = 4; + int cur_index = 0; + + for (i = 0; i < count; ++i) { + float minx, miny, maxx, maxy; + + minx = rects[i].x; + miny = rects[i].y; + maxx = rects[i].x + rects[i].w; + maxy = rects[i].y + rects[i].h; + + *ptr_xy++ = minx; + *ptr_xy++ = miny; + *ptr_xy++ = maxx; + *ptr_xy++ = miny; + *ptr_xy++ = maxx; + *ptr_xy++ = maxy; + *ptr_xy++ = minx; + *ptr_xy++ = maxy; + + *ptr_indices++ = cur_index + rect_index_order[0]; + *ptr_indices++ = cur_index + rect_index_order[1]; + *ptr_indices++ = cur_index + rect_index_order[2]; + *ptr_indices++ = cur_index + rect_index_order[3]; + *ptr_indices++ = cur_index + rect_index_order[4]; + *ptr_indices++ = cur_index + rect_index_order[5]; + cur_index += 4; + } + + result = renderer->QueueGeometry(renderer, cmd, NULL, + xy, xy_stride, &renderer->color, 0 /* color_stride */, NULL, 0, + num_vertices, indices, num_indices, size_indices, + 1.0f, 1.0f); + + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + + } else { + result = renderer->QueueFillRects(renderer, cmd, rects, count); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + } + return result; +} + +static bool QueueCmdCopy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect) +{ + SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY, texture); + bool result = false; + if (cmd) { + result = renderer->QueueCopy(renderer, cmd, texture, srcrect, dstrect); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + return result; +} + +static bool QueueCmdCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_FRect *srcquad, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) +{ + SDL_RenderCommand *cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_COPY_EX, texture); + bool result = false; + if (cmd) { + result = renderer->QueueCopyEx(renderer, cmd, texture, srcquad, dstrect, angle, center, flip, scale_x, scale_y); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + return result; +} + +static bool QueueCmdGeometry(SDL_Renderer *renderer, SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y, SDL_TextureAddressMode texture_address_mode) +{ + SDL_RenderCommand *cmd; + bool result = false; + cmd = PrepQueueCmdDraw(renderer, SDL_RENDERCMD_GEOMETRY, texture); + if (cmd) { + cmd->data.draw.texture_address_mode = texture_address_mode; + result = renderer->QueueGeometry(renderer, cmd, texture, + xy, xy_stride, + color, color_stride, uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + scale_x, scale_y); + if (!result) { + cmd->command = SDL_RENDERCMD_NO_OP; + } + } + return result; +} + +static void UpdateMainViewDimensions(SDL_Renderer *renderer) +{ + int window_w = 0, window_h = 0; + + if (renderer->window) { + SDL_GetWindowSize(renderer->window, &window_w, &window_h); + } + + SDL_GetRenderOutputSize(renderer, &renderer->main_view.pixel_w, &renderer->main_view.pixel_h); + + if (window_w > 0 && window_h > 0) { + renderer->dpi_scale.x = (float)renderer->main_view.pixel_w / window_w; + renderer->dpi_scale.y = (float)renderer->main_view.pixel_h / window_h; + } else { + renderer->dpi_scale.x = 1.0f; + renderer->dpi_scale.y = 1.0f; + } + UpdatePixelViewport(renderer, &renderer->main_view); +} + +static void UpdateColorScale(SDL_Renderer *renderer) +{ + float SDR_white_point; + if (renderer->target) { + SDR_white_point = renderer->target->SDR_white_point; + } else { + SDR_white_point = renderer->SDR_white_point; + } + renderer->color_scale = renderer->desired_color_scale * SDR_white_point; +} + +static void UpdateHDRProperties(SDL_Renderer *renderer) +{ + SDL_PropertiesID window_props; + SDL_PropertiesID renderer_props; + + window_props = SDL_GetWindowProperties(renderer->window); + if (!window_props) { + return; + } + + renderer_props = SDL_GetRendererProperties(renderer); + if (!renderer_props) { + return; + } + + if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + renderer->SDR_white_point = SDL_GetFloatProperty(window_props, SDL_PROP_WINDOW_SDR_WHITE_LEVEL_FLOAT, 1.0f); + renderer->HDR_headroom = SDL_GetFloatProperty(window_props, SDL_PROP_WINDOW_HDR_HEADROOM_FLOAT, 1.0f); + } else { + renderer->SDR_white_point = 1.0f; + renderer->HDR_headroom = 1.0f; + } + + if (renderer->HDR_headroom > 1.0f) { + SDL_SetBooleanProperty(renderer_props, SDL_PROP_RENDERER_HDR_ENABLED_BOOLEAN, true); + } else { + SDL_SetBooleanProperty(renderer_props, SDL_PROP_RENDERER_HDR_ENABLED_BOOLEAN, false); + } + SDL_SetFloatProperty(renderer_props, SDL_PROP_RENDERER_SDR_WHITE_POINT_FLOAT, renderer->SDR_white_point); + SDL_SetFloatProperty(renderer_props, SDL_PROP_RENDERER_HDR_HEADROOM_FLOAT, renderer->HDR_headroom); + + UpdateColorScale(renderer); +} + +static void UpdateLogicalPresentation(SDL_Renderer *renderer); + + +int SDL_GetNumRenderDrivers(void) +{ +#ifndef SDL_RENDER_DISABLED + return SDL_arraysize(render_drivers) - 1; +#else + return 0; +#endif +} + +const char *SDL_GetRenderDriver(int index) +{ +#ifndef SDL_RENDER_DISABLED + if (index < 0 || index >= SDL_GetNumRenderDrivers()) { + SDL_InvalidParamError("index"); + return NULL; + } + return render_drivers[index]->name; +#else + SDL_SetError("SDL not built with rendering support"); + return NULL; +#endif +} + +static bool SDL_RendererEventWatch(void *userdata, SDL_Event *event) +{ + SDL_Renderer *renderer = (SDL_Renderer *)userdata; + SDL_Window *window = renderer->window; + + if (renderer->WindowEvent) { + renderer->WindowEvent(renderer, &event->window); + } + + if (event->type == SDL_EVENT_WINDOW_RESIZED || + event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED || + event->type == SDL_EVENT_WINDOW_METAL_VIEW_RESIZED) { + SDL_RenderViewState *view = renderer->view; + renderer->view = &renderer->main_view; // only update the main_view (the window framebuffer) for window changes. + UpdateLogicalPresentation(renderer); + renderer->view = view; // put us back on whatever the current render target's actual view is. + } else if (event->type == SDL_EVENT_WINDOW_HIDDEN) { + renderer->hidden = true; + } else if (event->type == SDL_EVENT_WINDOW_SHOWN) { + if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) { + renderer->hidden = false; + } + } else if (event->type == SDL_EVENT_WINDOW_MINIMIZED) { + renderer->hidden = true; + } else if (event->type == SDL_EVENT_WINDOW_RESTORED || + event->type == SDL_EVENT_WINDOW_MAXIMIZED) { + if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) { + renderer->hidden = false; + } + } else if (event->type == SDL_EVENT_WINDOW_DISPLAY_CHANGED || + event->type == SDL_EVENT_WINDOW_HDR_STATE_CHANGED) { + UpdateHDRProperties(renderer); + } + return true; +} + +bool SDL_CreateWindowAndRenderer(const char *title, int width, int height, SDL_WindowFlags window_flags, SDL_Window **window, SDL_Renderer **renderer) +{ + bool hidden = (window_flags & SDL_WINDOW_HIDDEN) != 0; + + if (!window) { + return SDL_InvalidParamError("window"); + } + + if (!renderer) { + return SDL_InvalidParamError("renderer"); + } + + // Hide the window so if the renderer recreates it, we don't get a visual flash on screen + window_flags |= SDL_WINDOW_HIDDEN; + *window = SDL_CreateWindow(title, width, height, window_flags); + if (!*window) { + *renderer = NULL; + return false; + } + + *renderer = SDL_CreateRenderer(*window, NULL); + if (!*renderer) { + SDL_DestroyWindow(*window); + *window = NULL; + return false; + } + + if (!hidden) { + SDL_ShowWindow(*window); + } + + return true; +} + +#ifndef SDL_RENDER_DISABLED +static SDL_INLINE void VerifyDrawQueueFunctions(const SDL_Renderer *renderer) +{ + /* all of these functions are required to be implemented, even as no-ops, so we don't + have to check that they aren't NULL over and over. */ + SDL_assert(renderer->QueueSetViewport != NULL); + SDL_assert(renderer->QueueSetDrawColor != NULL); + SDL_assert(renderer->QueueDrawPoints != NULL); + SDL_assert(renderer->QueueDrawLines != NULL || renderer->QueueGeometry != NULL); + SDL_assert(renderer->QueueFillRects != NULL || renderer->QueueGeometry != NULL); + SDL_assert(renderer->QueueCopy != NULL || renderer->QueueGeometry != NULL); + SDL_assert(renderer->RunCommandQueue != NULL); +} + +static SDL_RenderLineMethod SDL_GetRenderLineMethod(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_RENDER_LINE_METHOD); + + int method = 0; + if (hint) { + method = SDL_atoi(hint); + } + switch (method) { + case 1: + return SDL_RENDERLINEMETHOD_POINTS; + case 2: + return SDL_RENDERLINEMETHOD_LINES; + case 3: + return SDL_RENDERLINEMETHOD_GEOMETRY; + default: + return SDL_RENDERLINEMETHOD_POINTS; + } +} + +static void SDL_CalculateSimulatedVSyncInterval(SDL_Renderer *renderer, SDL_Window *window) +{ + SDL_DisplayID displayID = SDL_GetDisplayForWindow(window); + const SDL_DisplayMode *mode; + int refresh_num, refresh_den; + + if (displayID == 0) { + displayID = SDL_GetPrimaryDisplay(); + } + mode = SDL_GetDesktopDisplayMode(displayID); + if (mode && mode->refresh_rate_numerator > 0 && mode->refresh_rate_denominator > 0) { + refresh_num = mode->refresh_rate_numerator; + refresh_den = mode->refresh_rate_denominator; + } else { + // Pick a good default refresh rate + refresh_num = 60; + refresh_den = 1; + } + // Flip numerator and denominator to change from framerate to interval + renderer->simulate_vsync_interval_ns = (SDL_NS_PER_SECOND * refresh_den) / refresh_num; +} + +#endif // !SDL_RENDER_DISABLED + + +SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props) +{ +#ifndef SDL_RENDER_DISABLED + SDL_Window *window = (SDL_Window *)SDL_GetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, NULL); + SDL_Surface *surface = (SDL_Surface *)SDL_GetPointerProperty(props, SDL_PROP_RENDERER_CREATE_SURFACE_POINTER, NULL); + const char *driver_name = SDL_GetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, NULL); + const char *hint; + SDL_PropertiesID new_props; + +#ifdef SDL_PLATFORM_ANDROID + if (!Android_WaitActiveAndLockActivity()) { + return NULL; + } +#endif + + SDL_Renderer *renderer = (SDL_Renderer *)SDL_calloc(1, sizeof(*renderer)); + if (!renderer) { + goto error; + } + + SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, true); + + if ((!window && !surface) || (window && surface)) { + SDL_InvalidParamError("window"); + goto error; + } + + if (window && SDL_WindowHasSurface(window)) { + SDL_SetError("Surface already associated with window"); + goto error; + } + + if (window && SDL_GetRenderer(window)) { + SDL_SetError("Renderer already associated with window"); + goto error; + } + + hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); + if (hint && *hint) { + SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, true)); + } + + if (surface) { +#ifdef SDL_VIDEO_RENDER_SW + const bool rc = SW_CreateRendererForSurface(renderer, surface, props); +#else + const bool rc = SDL_SetError("SDL not built with software renderer"); +#endif + if (!rc) { + goto error; + } + } else { + bool rc = false; + if (!driver_name) { + driver_name = SDL_GetHint(SDL_HINT_RENDER_DRIVER); + } + + if (driver_name && *driver_name != 0) { + const char *driver_attempt = driver_name; + while (driver_attempt && *driver_attempt != 0 && !rc) { + const char *driver_attempt_end = SDL_strchr(driver_attempt, ','); + const size_t driver_attempt_len = (driver_attempt_end) ? (driver_attempt_end - driver_attempt) : SDL_strlen(driver_attempt); + + for (int i = 0; render_drivers[i]; i++) { + const SDL_RenderDriver *driver = render_drivers[i]; + if ((driver_attempt_len == SDL_strlen(driver->name)) && (SDL_strncasecmp(driver->name, driver_attempt, driver_attempt_len) == 0)) { + rc = driver->CreateRenderer(renderer, window, props); + if (rc) { + break; + } + } + } + + driver_attempt = (driver_attempt_end) ? (driver_attempt_end + 1) : NULL; + } + } else { + for (int i = 0; render_drivers[i]; i++) { + const SDL_RenderDriver *driver = render_drivers[i]; + rc = driver->CreateRenderer(renderer, window, props); + if (rc) { + break; + } + SDL_DestroyRendererWithoutFreeing(renderer); + SDL_zerop(renderer); // make sure we don't leave function pointers from a previous CreateRenderer() in this struct. + } + } + + if (!rc) { + if (driver_name) { + SDL_SetError("%s not available", driver_name); + } else { + SDL_SetError("Couldn't find matching render driver"); + } + goto error; + } + } + + VerifyDrawQueueFunctions(renderer); + + renderer->window = window; + renderer->target_mutex = SDL_CreateMutex(); + if (surface) { + renderer->main_view.pixel_w = surface->w; + renderer->main_view.pixel_h = surface->h; + } + renderer->main_view.viewport.w = -1; + renderer->main_view.viewport.h = -1; + renderer->main_view.scale.x = 1.0f; + renderer->main_view.scale.y = 1.0f; + renderer->main_view.logical_scale.x = 1.0f; + renderer->main_view.logical_scale.y = 1.0f; + renderer->main_view.current_scale.x = 1.0f; + renderer->main_view.current_scale.y = 1.0f; + renderer->view = &renderer->main_view; + renderer->dpi_scale.x = 1.0f; + renderer->dpi_scale.y = 1.0f; + UpdatePixelViewport(renderer, &renderer->main_view); + UpdatePixelClipRect(renderer, &renderer->main_view); + UpdateMainViewDimensions(renderer); + + // new textures start at zero, so we start at 1 so first render doesn't flush by accident. + renderer->render_command_generation = 1; + + if (renderer->software) { + // Software renderer always uses line method, for speed + renderer->line_method = SDL_RENDERLINEMETHOD_LINES; + } else { + renderer->line_method = SDL_GetRenderLineMethod(); + } + + renderer->SDR_white_point = 1.0f; + renderer->HDR_headroom = 1.0f; + renderer->desired_color_scale = 1.0f; + renderer->color_scale = 1.0f; + + if (window) { + if (SDL_GetWindowFlags(window) & SDL_WINDOW_TRANSPARENT) { + renderer->transparent_window = true; + } + + if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN | SDL_WINDOW_MINIMIZED)) { + renderer->hidden = true; + } + } + + new_props = SDL_GetRendererProperties(renderer); + SDL_SetStringProperty(new_props, SDL_PROP_RENDERER_NAME_STRING, renderer->name); + if (window) { + SDL_SetPointerProperty(new_props, SDL_PROP_RENDERER_WINDOW_POINTER, window); + } + if (surface) { + SDL_SetPointerProperty(new_props, SDL_PROP_RENDERER_SURFACE_POINTER, surface); + } + SDL_SetNumberProperty(new_props, SDL_PROP_RENDERER_OUTPUT_COLORSPACE_NUMBER, renderer->output_colorspace); + UpdateHDRProperties(renderer); + + if (window) { + SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_RENDERER_POINTER, renderer); + SDL_AddWindowRenderer(window, renderer); + } + + SDL_SetRenderViewport(renderer, NULL); + + if (window) { + SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); + } + + int vsync = (int)SDL_GetNumberProperty(props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0); + if (!SDL_SetRenderVSync(renderer, vsync)) { + if (vsync == 0) { + // Some renderers require vsync enabled + SDL_SetRenderVSync(renderer, 1); + } + } + SDL_CalculateSimulatedVSyncInterval(renderer, window); + + SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, + "Created renderer: %s", renderer->name); + + renderer->next = SDL_renderers; + SDL_renderers = renderer; + +#ifdef SDL_PLATFORM_ANDROID + Android_UnlockActivityMutex(); +#endif + + SDL_ClearError(); + + return renderer; + +error: +#ifdef SDL_PLATFORM_ANDROID + Android_UnlockActivityMutex(); +#endif + + if (renderer) { + SDL_DestroyRenderer(renderer); + } + return NULL; + +#else + SDL_SetError("SDL not built with rendering support"); + return NULL; +#endif +} + +SDL_Renderer *SDL_CreateRenderer(SDL_Window *window, const char *name) +{ + SDL_Renderer *renderer; + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window); + SDL_SetStringProperty(props, SDL_PROP_RENDERER_CREATE_NAME_STRING, name); + renderer = SDL_CreateRendererWithProperties(props); + SDL_DestroyProperties(props); + return renderer; +} + +SDL_Renderer *SDL_CreateSoftwareRenderer(SDL_Surface *surface) +{ +#ifdef SDL_VIDEO_RENDER_SW + SDL_Renderer *renderer; + + if (!surface) { + SDL_InvalidParamError("surface"); + return NULL; + } + + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_SURFACE_POINTER, surface); + renderer = SDL_CreateRendererWithProperties(props); + SDL_DestroyProperties(props); + return renderer; +#else + SDL_SetError("SDL not built with rendering support"); + return NULL; +#endif // !SDL_RENDER_DISABLED +} + +SDL_Renderer *SDL_GetRenderer(SDL_Window *window) +{ + return (SDL_Renderer *)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_RENDERER_POINTER, NULL); +} + +SDL_Window *SDL_GetRenderWindow(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + return renderer->window; +} + +const char *SDL_GetRendererName(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + + return SDL_GetPersistentString(renderer->name); +} + +SDL_PropertiesID SDL_GetRendererProperties(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, 0); + + if (renderer->props == 0) { + renderer->props = SDL_CreateProperties(); + } + return renderer->props; +} + +bool SDL_GetRenderOutputSize(SDL_Renderer *renderer, int *w, int *h) +{ + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (renderer->GetOutputSize) { + return renderer->GetOutputSize(renderer, w, h); + } else if (renderer->window) { + return SDL_GetWindowSizeInPixels(renderer->window, w, h); + } else { + SDL_assert(!"This should never happen"); + return SDL_SetError("Renderer doesn't support querying output size"); + } +} + +bool SDL_GetCurrentRenderOutputSize(SDL_Renderer *renderer, int *w, int *h) +{ + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + const SDL_RenderViewState *view = renderer->view; + if (w) { + *w = view->pixel_w; + } + if (h) { + *h = view->pixel_h; + } + return true; +} + +static bool IsSupportedBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) +{ + switch (blendMode) { + // These are required to be supported by all renderers + case SDL_BLENDMODE_NONE: + case SDL_BLENDMODE_BLEND: + case SDL_BLENDMODE_BLEND_PREMULTIPLIED: + case SDL_BLENDMODE_ADD: + case SDL_BLENDMODE_ADD_PREMULTIPLIED: + case SDL_BLENDMODE_MOD: + case SDL_BLENDMODE_MUL: + return true; + + default: + return renderer->SupportsBlendMode && renderer->SupportsBlendMode(renderer, blendMode); + } +} + +static bool IsSupportedFormat(SDL_Renderer *renderer, SDL_PixelFormat format) +{ + int i; + + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == format) { + return true; + } + } + return false; +} + +static SDL_PixelFormat GetClosestSupportedFormat(SDL_Renderer *renderer, SDL_PixelFormat format) +{ + int i; + + if (format == SDL_PIXELFORMAT_MJPG) { + // We'll decode to SDL_PIXELFORMAT_NV12 or SDL_PIXELFORMAT_RGBA32 + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_NV12) { + return renderer->texture_formats[i]; + } + } + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_RGBA32) { + return renderer->texture_formats[i]; + } + } + } else if (SDL_ISPIXELFORMAT_FOURCC(format)) { + // Look for an exact match + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == format) { + return renderer->texture_formats[i]; + } + } + } else if (SDL_ISPIXELFORMAT_10BIT(format) || SDL_ISPIXELFORMAT_FLOAT(format)) { + if (SDL_ISPIXELFORMAT_10BIT(format)) { + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (SDL_ISPIXELFORMAT_10BIT(renderer->texture_formats[i])) { + return renderer->texture_formats[i]; + } + } + } + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (SDL_ISPIXELFORMAT_FLOAT(renderer->texture_formats[i])) { + return renderer->texture_formats[i]; + } + } + } else { + bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format); + + // We just want to match the first format that has the same channels + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (!SDL_ISPIXELFORMAT_FOURCC(renderer->texture_formats[i]) && + SDL_ISPIXELFORMAT_ALPHA(renderer->texture_formats[i]) == hasAlpha) { + return renderer->texture_formats[i]; + } + } + } + return renderer->texture_formats[0]; +} + +SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props) +{ + SDL_Texture *texture; + SDL_PixelFormat format = (SDL_PixelFormat)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, SDL_PIXELFORMAT_UNKNOWN); + SDL_TextureAccess access = (SDL_TextureAccess)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC); + int w = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, 0); + int h = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, 0); + SDL_Colorspace default_colorspace; + bool texture_is_fourcc_and_target; + + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (!format) { + format = renderer->texture_formats[0]; + } + if (SDL_BYTESPERPIXEL(format) == 0) { + SDL_SetError("Invalid texture format"); + return NULL; + } + if (SDL_ISPIXELFORMAT_INDEXED(format)) { + if (!IsSupportedFormat(renderer, format)) { + SDL_SetError("Palettized textures are not supported"); + return NULL; + } + } + if (w <= 0 || h <= 0) { + SDL_SetError("Texture dimensions can't be 0"); + return NULL; + } + int max_texture_size = (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 0); + if (max_texture_size && (w > max_texture_size || h > max_texture_size)) { + SDL_SetError("Texture dimensions are limited to %dx%d", max_texture_size, max_texture_size); + return NULL; + } + + default_colorspace = SDL_GetDefaultColorspaceForFormat(format); + + texture = (SDL_Texture *)SDL_calloc(1, sizeof(*texture)); + if (!texture) { + return NULL; + } + texture->refcount = 1; + SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, true); + texture->colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace); + texture->format = format; + texture->access = access; + texture->w = w; + texture->h = h; + texture->color.r = 1.0f; + texture->color.g = 1.0f; + texture->color.b = 1.0f; + texture->color.a = 1.0f; + texture->blendMode = SDL_ISPIXELFORMAT_ALPHA(format) ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE; + texture->scaleMode = SDL_SCALEMODE_LINEAR; + texture->view.pixel_w = w; + texture->view.pixel_h = h; + texture->view.viewport.w = -1; + texture->view.viewport.h = -1; + texture->view.scale.x = 1.0f; + texture->view.scale.y = 1.0f; + texture->view.logical_scale.x = 1.0f; + texture->view.logical_scale.y = 1.0f; + texture->view.current_scale.x = 1.0f; + texture->view.current_scale.y = 1.0f; + texture->renderer = renderer; + texture->next = renderer->textures; + if (renderer->textures) { + renderer->textures->prev = texture; + } + renderer->textures = texture; + + UpdatePixelViewport(renderer, &texture->view); + UpdatePixelClipRect(renderer, &texture->view); + + texture->SDR_white_point = SDL_GetFloatProperty(props, SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT, SDL_GetDefaultSDRWhitePoint(texture->colorspace)); + texture->HDR_headroom = SDL_GetFloatProperty(props, SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT, SDL_GetDefaultHDRHeadroom(texture->colorspace)); + + // FOURCC format cannot be used directly by renderer back-ends for target texture + texture_is_fourcc_and_target = (access == SDL_TEXTUREACCESS_TARGET && SDL_ISPIXELFORMAT_FOURCC(format)); + + if (!texture_is_fourcc_and_target && IsSupportedFormat(renderer, format)) { + if (!renderer->CreateTexture(renderer, texture, props)) { + SDL_DestroyTexture(texture); + return NULL; + } + } else { + SDL_PixelFormat closest_format; + SDL_PropertiesID native_props = SDL_CreateProperties(); + + if (!texture_is_fourcc_and_target) { + closest_format = GetClosestSupportedFormat(renderer, format); + } else { + closest_format = renderer->texture_formats[0]; + } + + if (format == SDL_PIXELFORMAT_MJPG && closest_format == SDL_PIXELFORMAT_NV12) { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, SDL_COLORSPACE_JPEG); + } else { + default_colorspace = SDL_GetDefaultColorspaceForFormat(closest_format); + if (SDL_COLORSPACETYPE(texture->colorspace) == SDL_COLORSPACETYPE(default_colorspace)) { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, texture->colorspace); + } else { + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace); + } + } + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, closest_format); + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, texture->access); + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, texture->w); + SDL_SetNumberProperty(native_props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, texture->h); + + texture->native = SDL_CreateTextureWithProperties(renderer, native_props); + SDL_DestroyProperties(native_props); + if (!texture->native) { + SDL_DestroyTexture(texture); + return NULL; + } + + SDL_SetPointerProperty(SDL_GetTextureProperties(texture->native), SDL_PROP_TEXTURE_PARENT_POINTER, texture); + + // Swap textures to have texture before texture->native in the list + texture->native->next = texture->next; + if (texture->native->next) { + texture->native->next->prev = texture->native; + } + texture->prev = texture->native->prev; + if (texture->prev) { + texture->prev->next = texture; + } + texture->native->prev = texture; + texture->next = texture->native; + renderer->textures = texture; + + if (texture->format == SDL_PIXELFORMAT_MJPG) { + // We have a custom decode + upload path for this + } else if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { +#ifdef SDL_HAVE_YUV + texture->yuv = SDL_SW_CreateYUVTexture(texture->format, texture->colorspace, w, h); +#else + SDL_SetError("SDL not built with YUV support"); +#endif + if (!texture->yuv) { + SDL_DestroyTexture(texture); + return NULL; + } + } else if (access == SDL_TEXTUREACCESS_STREAMING) { + // The pitch is 4 byte aligned + texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); + texture->pixels = SDL_calloc(1, (size_t)texture->pitch * h); + if (!texture->pixels) { + SDL_DestroyTexture(texture); + return NULL; + } + } + } + + // Now set the properties for the new texture + props = SDL_GetTextureProperties(texture); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_COLORSPACE_NUMBER, texture->colorspace); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_FORMAT_NUMBER, texture->format); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_ACCESS_NUMBER, texture->access); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_WIDTH_NUMBER, texture->w); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_HEIGHT_NUMBER, texture->h); + SDL_SetFloatProperty(props, SDL_PROP_TEXTURE_SDR_WHITE_POINT_FLOAT, texture->SDR_white_point); + if (texture->HDR_headroom > 0.0f) { + SDL_SetFloatProperty(props, SDL_PROP_TEXTURE_HDR_HEADROOM_FLOAT, texture->HDR_headroom); + } + return texture; +} + +SDL_Texture *SDL_CreateTexture(SDL_Renderer *renderer, SDL_PixelFormat format, SDL_TextureAccess access, int w, int h) +{ + SDL_Texture *texture; + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, format); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, access); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, w); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, h); + texture = SDL_CreateTextureWithProperties(renderer, props); + SDL_DestroyProperties(props); + return texture; +} + +static bool SDL_UpdateTextureFromSurface(SDL_Texture *texture, SDL_Rect *rect, SDL_Surface *surface) +{ + SDL_TextureAccess access; + bool direct_update; + SDL_PixelFormat tex_format; + SDL_PropertiesID surface_props; + SDL_PropertiesID tex_props; + SDL_Colorspace surface_colorspace = SDL_COLORSPACE_UNKNOWN; + SDL_Colorspace texture_colorspace = SDL_COLORSPACE_UNKNOWN; + + if (texture == NULL || surface == NULL) { + return false; + } + + tex_props = SDL_GetTextureProperties(texture); + if (!tex_props) { + return false; + } + + surface_props = SDL_GetSurfaceProperties(surface); + if (!surface_props) { + return false; + } + + tex_format = (SDL_PixelFormat)SDL_GetNumberProperty(tex_props, SDL_PROP_TEXTURE_FORMAT_NUMBER, 0); + access = (SDL_TextureAccess)SDL_GetNumberProperty(tex_props, SDL_PROP_TEXTURE_ACCESS_NUMBER, 0); + + if (access != SDL_TEXTUREACCESS_STATIC && access != SDL_TEXTUREACCESS_STREAMING) { + return false; + } + + surface_colorspace = SDL_GetSurfaceColorspace(surface); + texture_colorspace = surface_colorspace; + + if (surface_colorspace == SDL_COLORSPACE_SRGB_LINEAR || + SDL_COLORSPACETRANSFER(surface_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) { + if (SDL_ISPIXELFORMAT_FLOAT(tex_format)) { + texture_colorspace = SDL_COLORSPACE_SRGB_LINEAR; + } else if (SDL_ISPIXELFORMAT_10BIT(tex_format)) { + texture_colorspace = SDL_COLORSPACE_HDR10; + } else { + texture_colorspace = SDL_COLORSPACE_SRGB; + } + } + + if (tex_format == surface->format && texture_colorspace == surface_colorspace) { + if (SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) { + /* Surface and Renderer formats are identical. + * Intermediate conversion is needed to convert color key to alpha (SDL_ConvertColorkeyToAlpha()). */ + direct_update = false; + } else { + // Update Texture directly + direct_update = true; + } + } else { + // Surface and Renderer formats are different, it needs an intermediate conversion. + direct_update = false; + } + + if (direct_update) { + if (SDL_MUSTLOCK(surface)) { + SDL_LockSurface(surface); + SDL_UpdateTexture(texture, rect, surface->pixels, surface->pitch); + SDL_UnlockSurface(surface); + } else { + SDL_UpdateTexture(texture, rect, surface->pixels, surface->pitch); + } + } else { + SDL_Surface *temp = NULL; + + // Set up a destination surface for the texture update + temp = SDL_ConvertSurfaceAndColorspace(surface, tex_format, NULL, texture_colorspace, surface_props); + if (temp) { + SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); + SDL_DestroySurface(temp); + } else { + return false; + } + } + + { + Uint8 r, g, b, a; + SDL_BlendMode blendMode; + + SDL_GetSurfaceColorMod(surface, &r, &g, &b); + SDL_SetTextureColorMod(texture, r, g, b); + + SDL_GetSurfaceAlphaMod(surface, &a); + SDL_SetTextureAlphaMod(texture, a); + + if (SDL_SurfaceHasColorKey(surface)) { + // We converted to a texture with alpha format + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + } else { + SDL_GetSurfaceBlendMode(surface, &blendMode); + SDL_SetTextureBlendMode(texture, blendMode); + } + } + + return true; +} + +SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *surface) +{ + bool needAlpha; + int i; + SDL_PixelFormat format = SDL_PIXELFORMAT_UNKNOWN; + SDL_Palette *palette; + SDL_Texture *texture; + SDL_PropertiesID props; + SDL_Colorspace surface_colorspace = SDL_COLORSPACE_UNKNOWN; + SDL_Colorspace texture_colorspace = SDL_COLORSPACE_UNKNOWN; + + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (!SDL_SurfaceValid(surface)) { + SDL_InvalidParamError("SDL_CreateTextureFromSurface(): surface"); + return NULL; + } + + // See what the best texture format is + if (SDL_ISPIXELFORMAT_ALPHA(surface->format) || SDL_SurfaceHasColorKey(surface)) { + needAlpha = true; + } else { + needAlpha = false; + } + + // If Palette contains alpha values, promotes to alpha format + palette = SDL_GetSurfacePalette(surface); + if (palette) { + bool is_opaque, has_alpha_channel; + SDL_DetectPalette(palette, &is_opaque, &has_alpha_channel); + if (!is_opaque) { + needAlpha = true; + } + } + + surface_colorspace = SDL_GetSurfaceColorspace(surface); + + // Try to have the best pixel format for the texture + // No alpha, but a colorkey => promote to alpha + if (!SDL_ISPIXELFORMAT_ALPHA(surface->format) && SDL_SurfaceHasColorKey(surface)) { + if (surface->format == SDL_PIXELFORMAT_XRGB8888) { + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_ARGB8888) { + format = SDL_PIXELFORMAT_ARGB8888; + break; + } + } + } else if (surface->format == SDL_PIXELFORMAT_XBGR8888) { + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == SDL_PIXELFORMAT_ABGR8888) { + format = SDL_PIXELFORMAT_ABGR8888; + break; + } + } + } + } else { + // Exact match would be fine + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (renderer->texture_formats[i] == surface->format) { + format = surface->format; + break; + } + } + } + + // Look for 10-bit pixel formats if needed + if (format == SDL_PIXELFORMAT_UNKNOWN && SDL_ISPIXELFORMAT_10BIT(surface->format)) { + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (SDL_ISPIXELFORMAT_10BIT(renderer->texture_formats[i])) { + format = renderer->texture_formats[i]; + break; + } + } + } + + // Look for floating point pixel formats if needed + if (format == SDL_PIXELFORMAT_UNKNOWN && + (SDL_ISPIXELFORMAT_10BIT(surface->format) || SDL_ISPIXELFORMAT_FLOAT(surface->format))) { + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (SDL_ISPIXELFORMAT_FLOAT(renderer->texture_formats[i])) { + format = renderer->texture_formats[i]; + break; + } + } + } + + // Fallback, choose a valid pixel format + if (format == SDL_PIXELFORMAT_UNKNOWN) { + format = renderer->texture_formats[0]; + for (i = 0; i < renderer->num_texture_formats; ++i) { + if (!SDL_ISPIXELFORMAT_FOURCC(renderer->texture_formats[i]) && + SDL_ISPIXELFORMAT_ALPHA(renderer->texture_formats[i]) == needAlpha) { + format = renderer->texture_formats[i]; + break; + } + } + } + + if (surface_colorspace == SDL_COLORSPACE_SRGB_LINEAR || + SDL_COLORSPACETRANSFER(surface_colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) { + if (SDL_ISPIXELFORMAT_FLOAT(format)) { + texture_colorspace = SDL_COLORSPACE_SRGB_LINEAR; + } else if (SDL_ISPIXELFORMAT_10BIT(format)) { + texture_colorspace = SDL_COLORSPACE_HDR10; + } else { + texture_colorspace = SDL_COLORSPACE_SRGB; + } + } + + props = SDL_CreateProperties(); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, texture_colorspace); + if (surface_colorspace == texture_colorspace) { + SDL_SetFloatProperty(props, SDL_PROP_TEXTURE_CREATE_SDR_WHITE_POINT_FLOAT, + SDL_GetSurfaceSDRWhitePoint(surface, surface_colorspace)); + } + SDL_SetFloatProperty(props, SDL_PROP_TEXTURE_CREATE_HDR_HEADROOM_FLOAT, + SDL_GetSurfaceHDRHeadroom(surface, surface_colorspace)); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, format); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, surface->w); + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, surface->h); + texture = SDL_CreateTextureWithProperties(renderer, props); + SDL_DestroyProperties(props); + if (!texture) { + return NULL; + } + + if (!SDL_UpdateTextureFromSurface(texture, NULL, surface)) { + SDL_DestroyTexture(texture); + return NULL; + } + + return texture; +} + +SDL_Renderer *SDL_GetRendererFromTexture(SDL_Texture *texture) +{ + CHECK_TEXTURE_MAGIC(texture, NULL); + + return texture->renderer; +} + +SDL_PropertiesID SDL_GetTextureProperties(SDL_Texture *texture) +{ + CHECK_TEXTURE_MAGIC(texture, 0); + + if (texture->props == 0) { + texture->props = SDL_CreateProperties(); + } + return texture->props; +} + +bool SDL_GetTextureSize(SDL_Texture *texture, float *w, float *h) +{ + if (w) { + *w = 0; + } + if (h) { + *h = 0; + } + + CHECK_TEXTURE_MAGIC(texture, false); + + if (w) { + *w = (float)texture->w; + } + if (h) { + *h = (float)texture->h; + } + return true; +} + +bool SDL_SetTextureColorMod(SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b) +{ + const float fR = (float)r / 255.0f; + const float fG = (float)g / 255.0f; + const float fB = (float)b / 255.0f; + + return SDL_SetTextureColorModFloat(texture, fR, fG, fB); +} + +bool SDL_SetTextureColorModFloat(SDL_Texture *texture, float r, float g, float b) +{ + CHECK_TEXTURE_MAGIC(texture, false); + + texture->color.r = r; + texture->color.g = g; + texture->color.b = b; + if (texture->native) { + return SDL_SetTextureColorModFloat(texture->native, r, g, b); + } + return true; +} + +bool SDL_GetTextureColorMod(SDL_Texture *texture, Uint8 *r, Uint8 *g, Uint8 *b) +{ + float fR = 1.0f, fG = 1.0f, fB = 1.0f; + + if (!SDL_GetTextureColorModFloat(texture, &fR, &fG, &fB)) { + if (r) { + *r = 255; + } + if (g) { + *g = 255; + } + if (b) { + *b = 255; + } + return false; + } + + if (r) { + *r = (Uint8)SDL_roundf(SDL_clamp(fR, 0.0f, 1.0f) * 255.0f); + } + if (g) { + *g = (Uint8)SDL_roundf(SDL_clamp(fG, 0.0f, 1.0f) * 255.0f); + } + if (b) { + *b = (Uint8)SDL_roundf(SDL_clamp(fB, 0.0f, 1.0f) * 255.0f); + } + return true; +} + +bool SDL_GetTextureColorModFloat(SDL_Texture *texture, float *r, float *g, float *b) +{ + SDL_FColor color; + + if (r) { + *r = 1.0f; + } + if (g) { + *g = 1.0f; + } + if (b) { + *b = 1.0f; + } + + CHECK_TEXTURE_MAGIC(texture, false); + + color = texture->color; + + if (r) { + *r = color.r; + } + if (g) { + *g = color.g; + } + if (b) { + *b = color.b; + } + return true; +} + +bool SDL_SetTextureAlphaMod(SDL_Texture *texture, Uint8 alpha) +{ + const float fA = (float)alpha / 255.0f; + + return SDL_SetTextureAlphaModFloat(texture, fA); +} + +bool SDL_SetTextureAlphaModFloat(SDL_Texture *texture, float alpha) +{ + CHECK_TEXTURE_MAGIC(texture, false); + + texture->color.a = alpha; + if (texture->native) { + return SDL_SetTextureAlphaModFloat(texture->native, alpha); + } + return true; +} + +bool SDL_GetTextureAlphaMod(SDL_Texture *texture, Uint8 *alpha) +{ + float fA = 1.0f; + + if (!SDL_GetTextureAlphaModFloat(texture, &fA)) { + if (alpha) { + *alpha = 255; + } + return false; + } + + if (alpha) { + *alpha = (Uint8)SDL_roundf(SDL_clamp(fA, 0.0f, 1.0f) * 255.0f); + } + return true; +} + +bool SDL_GetTextureAlphaModFloat(SDL_Texture *texture, float *alpha) +{ + if (alpha) { + *alpha = 1.0f; + } + + CHECK_TEXTURE_MAGIC(texture, false); + + if (alpha) { + *alpha = texture->color.a; + } + return true; +} + +bool SDL_SetTextureBlendMode(SDL_Texture *texture, SDL_BlendMode blendMode) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (blendMode == SDL_BLENDMODE_INVALID) { + return SDL_InvalidParamError("blendMode"); + } + + renderer = texture->renderer; + if (!IsSupportedBlendMode(renderer, blendMode)) { + return SDL_Unsupported(); + } + texture->blendMode = blendMode; + if (texture->native) { + return SDL_SetTextureBlendMode(texture->native, blendMode); + } + return true; +} + +bool SDL_GetTextureBlendMode(SDL_Texture *texture, SDL_BlendMode *blendMode) +{ + if (blendMode) { + *blendMode = SDL_BLENDMODE_INVALID; + } + + CHECK_TEXTURE_MAGIC(texture, false); + + if (blendMode) { + *blendMode = texture->blendMode; + } + return true; +} + +bool SDL_SetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode scaleMode) +{ + SDL_Renderer *renderer; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (scaleMode != SDL_SCALEMODE_NEAREST && + scaleMode != SDL_SCALEMODE_LINEAR) { + return SDL_InvalidParamError("scaleMode"); + } + + renderer = texture->renderer; + texture->scaleMode = scaleMode; + if (texture->native) { + return SDL_SetTextureScaleMode(texture->native, scaleMode); + } else { + renderer->SetTextureScaleMode(renderer, texture, scaleMode); + } + return true; +} + +bool SDL_GetTextureScaleMode(SDL_Texture *texture, SDL_ScaleMode *scaleMode) +{ + if (scaleMode) { + *scaleMode = SDL_SCALEMODE_LINEAR; + } + + CHECK_TEXTURE_MAGIC(texture, false); + + if (scaleMode) { + *scaleMode = texture->scaleMode; + } + return true; +} + +#ifdef SDL_HAVE_YUV +static bool SDL_UpdateTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, + const void *pixels, int pitch) +{ + SDL_Texture *native = texture->native; + SDL_Rect full_rect; + + if (!SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch)) { + return false; + } + + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + // We can lock the texture and copy to it + void *native_pixels = NULL; + int native_pitch = 0; + + if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, native_pixels, native_pitch); + SDL_UnlockTexture(native); + } else { + // Use a temporary buffer for updating + const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); + const size_t alloclen = (size_t)rect->h * temp_pitch; + if (alloclen > 0) { + void *temp_pixels = SDL_malloc(alloclen); + if (!temp_pixels) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, temp_pixels, temp_pitch); + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + SDL_free(temp_pixels); + } + } + return true; +} +#endif // SDL_HAVE_YUV + +static bool SDL_UpdateTextureNative(SDL_Texture *texture, const SDL_Rect *rect, + const void *pixels, int pitch) +{ + SDL_Texture *native = texture->native; + + if (!rect->w || !rect->h) { + return true; // nothing to do. + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + // We can lock the texture and copy to it + void *native_pixels = NULL; + int native_pitch = 0; + + if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { + return false; + } + SDL_ConvertPixelsAndColorspace(rect->w, rect->h, + texture->format, texture->colorspace, 0, pixels, pitch, + native->format, native->colorspace, 0, native_pixels, native_pitch); + SDL_UnlockTexture(native); + } else { + // Use a temporary buffer for updating + const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); + const size_t alloclen = (size_t)rect->h * temp_pitch; + if (alloclen > 0) { + void *temp_pixels = SDL_malloc(alloclen); + if (!temp_pixels) { + return false; + } + SDL_ConvertPixelsAndColorspace(rect->w, rect->h, + texture->format, texture->colorspace, 0, pixels, pitch, + native->format, native->colorspace, 0, temp_pixels, temp_pitch); + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + SDL_free(temp_pixels); + } + } + return true; +} + +bool SDL_UpdateTexture(SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch) +{ + SDL_Rect real_rect; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (!pixels) { + return SDL_InvalidParamError("pixels"); + } + if (!pitch) { + return SDL_InvalidParamError("pitch"); + } + + real_rect.x = 0; + real_rect.y = 0; + real_rect.w = texture->w; + real_rect.h = texture->h; + if (rect) { + if (!SDL_GetRectIntersection(rect, &real_rect, &real_rect)) { + return true; + } + } + + if (real_rect.w == 0 || real_rect.h == 0) { + return true; // nothing to do. +#ifdef SDL_HAVE_YUV + } else if (texture->yuv) { + return SDL_UpdateTextureYUV(texture, &real_rect, pixels, pitch); +#endif + } else if (texture->native) { + return SDL_UpdateTextureNative(texture, &real_rect, pixels, pitch); + } else { + SDL_Renderer *renderer = texture->renderer; + if (!FlushRenderCommandsIfTextureNeeded(texture)) { + return false; + } + return renderer->UpdateTexture(renderer, texture, &real_rect, pixels, pitch); + } +} + +#ifdef SDL_HAVE_YUV +static bool SDL_UpdateTextureYUVPlanar(SDL_Texture *texture, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) +{ + SDL_Texture *native = texture->native; + SDL_Rect full_rect; + + if (!SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch)) { + return false; + } + + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + + if (!rect->w || !rect->h) { + return true; // nothing to do. + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + // We can lock the texture and copy to it + void *native_pixels = NULL; + int native_pitch = 0; + + if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, native_pixels, native_pitch); + SDL_UnlockTexture(native); + } else { + // Use a temporary buffer for updating + const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); + const size_t alloclen = (size_t)rect->h * temp_pitch; + if (alloclen > 0) { + void *temp_pixels = SDL_malloc(alloclen); + if (!temp_pixels) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, temp_pixels, temp_pitch); + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + SDL_free(temp_pixels); + } + } + return true; +} + +static bool SDL_UpdateTextureNVPlanar(SDL_Texture *texture, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ + SDL_Texture *native = texture->native; + SDL_Rect full_rect; + + if (!SDL_SW_UpdateNVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, UVplane, UVpitch)) { + return false; + } + + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + + if (!rect->w || !rect->h) { + return true; // nothing to do. + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + // We can lock the texture and copy to it + void *native_pixels = NULL; + int native_pitch = 0; + + if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, native_pixels, native_pitch); + SDL_UnlockTexture(native); + } else { + // Use a temporary buffer for updating + const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); + const size_t alloclen = (size_t)rect->h * temp_pitch; + if (alloclen > 0) { + void *temp_pixels = SDL_malloc(alloclen); + if (!temp_pixels) { + return false; + } + SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, + rect->w, rect->h, temp_pixels, temp_pitch); + SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); + SDL_free(temp_pixels); + } + } + return true; +} + +#endif // SDL_HAVE_YUV + +bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) +{ +#ifdef SDL_HAVE_YUV + SDL_Renderer *renderer; + SDL_Rect real_rect; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (!Yplane) { + return SDL_InvalidParamError("Yplane"); + } + if (!Ypitch) { + return SDL_InvalidParamError("Ypitch"); + } + if (!Uplane) { + return SDL_InvalidParamError("Uplane"); + } + if (!Upitch) { + return SDL_InvalidParamError("Upitch"); + } + if (!Vplane) { + return SDL_InvalidParamError("Vplane"); + } + if (!Vpitch) { + return SDL_InvalidParamError("Vpitch"); + } + + if (texture->format != SDL_PIXELFORMAT_YV12 && + texture->format != SDL_PIXELFORMAT_IYUV) { + return SDL_SetError("Texture format must by YV12 or IYUV"); + } + + real_rect.x = 0; + real_rect.y = 0; + real_rect.w = texture->w; + real_rect.h = texture->h; + if (rect) { + SDL_GetRectIntersection(rect, &real_rect, &real_rect); + } + + if (real_rect.w == 0 || real_rect.h == 0) { + return true; // nothing to do. + } + + if (texture->yuv) { + return SDL_UpdateTextureYUVPlanar(texture, &real_rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); + } else { + SDL_assert(!texture->native); + renderer = texture->renderer; + SDL_assert(renderer->UpdateTextureYUV); + if (renderer->UpdateTextureYUV) { + if (!FlushRenderCommandsIfTextureNeeded(texture)) { + return false; + } + return renderer->UpdateTextureYUV(renderer, texture, &real_rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); + } else { + return SDL_Unsupported(); + } + } +#else + return false; +#endif +} + +bool SDL_UpdateNVTexture(SDL_Texture *texture, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ +#ifdef SDL_HAVE_YUV + SDL_Renderer *renderer; + SDL_Rect real_rect; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (!Yplane) { + return SDL_InvalidParamError("Yplane"); + } + if (!Ypitch) { + return SDL_InvalidParamError("Ypitch"); + } + if (!UVplane) { + return SDL_InvalidParamError("UVplane"); + } + if (!UVpitch) { + return SDL_InvalidParamError("UVpitch"); + } + + if (texture->format != SDL_PIXELFORMAT_NV12 && + texture->format != SDL_PIXELFORMAT_NV21) { + return SDL_SetError("Texture format must by NV12 or NV21"); + } + + real_rect.x = 0; + real_rect.y = 0; + real_rect.w = texture->w; + real_rect.h = texture->h; + if (rect) { + SDL_GetRectIntersection(rect, &real_rect, &real_rect); + } + + if (real_rect.w == 0 || real_rect.h == 0) { + return true; // nothing to do. + } + + if (texture->yuv) { + return SDL_UpdateTextureNVPlanar(texture, &real_rect, Yplane, Ypitch, UVplane, UVpitch); + } else { + SDL_assert(!texture->native); + renderer = texture->renderer; + SDL_assert(renderer->UpdateTextureNV); + if (renderer->UpdateTextureNV) { + if (!FlushRenderCommandsIfTextureNeeded(texture)) { + return false; + } + return renderer->UpdateTextureNV(renderer, texture, &real_rect, Yplane, Ypitch, UVplane, UVpitch); + } else { + return SDL_Unsupported(); + } + } +#else + return false; +#endif +} + +#ifdef SDL_HAVE_YUV +static bool SDL_LockTextureYUV(SDL_Texture *texture, const SDL_Rect *rect, + void **pixels, int *pitch) +{ + return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch); +} +#endif // SDL_HAVE_YUV + +static bool SDL_LockTextureNative(SDL_Texture *texture, const SDL_Rect *rect, + void **pixels, int *pitch) +{ + texture->locked_rect = *rect; + *pixels = (void *)((Uint8 *)texture->pixels + + rect->y * texture->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = texture->pitch; + return true; +} + +bool SDL_LockTexture(SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch) +{ + SDL_Rect full_rect; + + CHECK_TEXTURE_MAGIC(texture, false); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + return SDL_SetError("SDL_LockTexture(): texture must be streaming"); + } + + if (!rect) { + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = texture->w; + full_rect.h = texture->h; + rect = &full_rect; + } + +#ifdef SDL_HAVE_YUV + if (texture->yuv) { + if (!FlushRenderCommandsIfTextureNeeded(texture)) { + return false; + } + return SDL_LockTextureYUV(texture, rect, pixels, pitch); + } else +#endif + if (texture->native) { + // Calls a real SDL_LockTexture/SDL_UnlockTexture on unlock, flushing then. + return SDL_LockTextureNative(texture, rect, pixels, pitch); + } else { + SDL_Renderer *renderer = texture->renderer; + if (!FlushRenderCommandsIfTextureNeeded(texture)) { + return false; + } + return renderer->LockTexture(renderer, texture, rect, pixels, pitch); + } +} + +bool SDL_LockTextureToSurface(SDL_Texture *texture, const SDL_Rect *rect, SDL_Surface **surface) +{ + SDL_Rect real_rect; + void *pixels = NULL; + int pitch = 0; // fix static analysis + + if (!texture || !surface) { + return false; + } + + real_rect.x = 0; + real_rect.y = 0; + real_rect.w = texture->w; + real_rect.h = texture->h; + if (rect) { + SDL_GetRectIntersection(rect, &real_rect, &real_rect); + } + + if (!SDL_LockTexture(texture, &real_rect, &pixels, &pitch)) { + return false; + } + + texture->locked_surface = SDL_CreateSurfaceFrom(real_rect.w, real_rect.h, texture->format, pixels, pitch); + if (!texture->locked_surface) { + SDL_UnlockTexture(texture); + return false; + } + + *surface = texture->locked_surface; + return true; +} + +#ifdef SDL_HAVE_YUV +static void SDL_UnlockTextureYUV(SDL_Texture *texture) +{ + SDL_Texture *native = texture->native; + void *native_pixels = NULL; + int native_pitch = 0; + SDL_Rect rect; + + rect.x = 0; + rect.y = 0; + rect.w = texture->w; + rect.h = texture->h; + + if (!SDL_LockTexture(native, &rect, &native_pixels, &native_pitch)) { + return; + } + SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format, + rect.w, rect.h, native_pixels, native_pitch); + SDL_UnlockTexture(native); +} +#endif // SDL_HAVE_YUV + +static void SDL_UnlockTextureNative(SDL_Texture *texture) +{ + SDL_Texture *native = texture->native; + void *native_pixels = NULL; + int native_pitch = 0; + const SDL_Rect *rect = &texture->locked_rect; + const void *pixels = (void *)((Uint8 *)texture->pixels + + rect->y * texture->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + int pitch = texture->pitch; + + if (!SDL_LockTexture(native, rect, &native_pixels, &native_pitch)) { + return; + } + SDL_ConvertPixels(rect->w, rect->h, + texture->format, pixels, pitch, + native->format, native_pixels, native_pitch); + SDL_UnlockTexture(native); +} + +void SDL_UnlockTexture(SDL_Texture *texture) +{ + CHECK_TEXTURE_MAGIC(texture,); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + return; + } +#ifdef SDL_HAVE_YUV + if (texture->yuv) { + SDL_UnlockTextureYUV(texture); + } else +#endif + if (texture->native) { + SDL_UnlockTextureNative(texture); + } else { + SDL_Renderer *renderer = texture->renderer; + renderer->UnlockTexture(renderer, texture); + } + + SDL_DestroySurface(texture->locked_surface); + texture->locked_surface = NULL; +} + +bool SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) +{ + // texture == NULL is valid and means reset the target to the window + if (texture) { + CHECK_TEXTURE_MAGIC(texture, false); + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + if (texture->access != SDL_TEXTUREACCESS_TARGET) { + return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET"); + } + if (texture->native) { + // Always render to the native texture + texture = texture->native; + } + } + + if (texture == renderer->target) { + // Nothing to do! + return true; + } + + FlushRenderCommands(renderer); // time to send everything to the GPU! + + SDL_LockMutex(renderer->target_mutex); + + renderer->target = texture; + if (texture) { + renderer->view = &texture->view; + } else { + renderer->view = &renderer->main_view; + } + UpdateColorScale(renderer); + + if (!renderer->SetRenderTarget(renderer, texture)) { + SDL_UnlockMutex(renderer->target_mutex); + return false; + } + + SDL_UnlockMutex(renderer->target_mutex); + + if (!QueueCmdSetViewport(renderer)) { + return false; + } + if (!QueueCmdSetClipRect(renderer)) { + return false; + } + + // All set! + return true; +} + +SDL_Texture *SDL_GetRenderTarget(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + if (!renderer->target) { + return NULL; + } + return (SDL_Texture *) SDL_GetPointerProperty(SDL_GetTextureProperties(renderer->target), SDL_PROP_TEXTURE_PARENT_POINTER, renderer->target); +} + +static void UpdateLogicalPresentation(SDL_Renderer *renderer) +{ + SDL_RenderViewState *view = renderer->view; + const bool is_main_view = (view == &renderer->main_view); + const float logical_w = view->logical_w; + const float logical_h = view->logical_h; + int iwidth, iheight; + + if (renderer->target) { + iwidth = (int)renderer->target->w; + iheight = (int)renderer->target->h; + } else { + SDL_GetRenderOutputSize(renderer, &iwidth, &iheight); + } + + view->logical_src_rect.x = 0.0f; + view->logical_src_rect.y = 0.0f; + view->logical_src_rect.w = logical_w; + view->logical_src_rect.h = logical_h; + + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_DISABLED) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = iwidth; + view->logical_dst_rect.h = iheight; + view->logical_offset.x = view->logical_offset.y = 0.0f; + view->logical_scale.x = view->logical_scale.y = 1.0f; + view->current_scale.x = view->scale.x; // skip the multiplications against 1.0f. + view->current_scale.y = view->scale.y; + } else { + const float output_w = (float)iwidth; + const float output_h = (float)iheight; + const float want_aspect = logical_w / logical_h; + const float real_aspect = output_w / output_h; + + if ((logical_w <= 0.0f) || (logical_h <= 0.0f)) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = output_h; + } else if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE) { + float scale; + if (want_aspect > real_aspect) { + scale = (float)((int)output_w / (int)logical_w); // This an integer division! + } else { + scale = (float)((int)output_h / (int)logical_h); // This an integer division! + } + + if (scale < 1.0f) { + scale = 1.0f; + } + + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + + } else if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_STRETCH || SDL_fabsf(want_aspect - real_aspect) < 0.0001f) { + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = output_h; + + } else if (want_aspect > real_aspect) { + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { + // We want a wider aspect ratio than is available - letterbox it + const float scale = output_w / logical_w; + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + } else { // view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN + /* We want a wider aspect ratio than is available - + zoom so logical height matches the real height + and the width will grow off the screen + */ + const float scale = output_h / logical_h; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.h = output_h; + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + } + } else { + if (view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { + // We want a narrower aspect ratio than is available - use side-bars + const float scale = output_h / logical_h; + view->logical_dst_rect.y = 0.0f; + view->logical_dst_rect.h = output_h; + view->logical_dst_rect.w = SDL_floorf(logical_w * scale); + view->logical_dst_rect.x = (output_w - view->logical_dst_rect.w) / 2.0f; + } else { // view->logical_presentation_mode == SDL_LOGICAL_PRESENTATION_OVERSCAN + /* We want a narrower aspect ratio than is available - + zoom so logical width matches the real width + and the height will grow off the screen + */ + const float scale = output_w / logical_w; + view->logical_dst_rect.x = 0.0f; + view->logical_dst_rect.w = output_w; + view->logical_dst_rect.h = SDL_floorf(logical_h * scale); + view->logical_dst_rect.y = (output_h - view->logical_dst_rect.h) / 2.0f; + } + } + + view->logical_scale.x = (logical_w > 0.0f) ? view->logical_dst_rect.w / logical_w : 0.0f; + view->logical_scale.y = (logical_h > 0.0f) ? view->logical_dst_rect.h / logical_h : 0.0f; + view->current_scale.x = view->scale.x * view->logical_scale.x; + view->current_scale.y = view->scale.y * view->logical_scale.y; + view->logical_offset.x = view->logical_dst_rect.x; + view->logical_offset.y = view->logical_dst_rect.y; + } + + if (is_main_view) { + // This makes sure the dpi_scale is right. It also sets pixel_w and pixel_h, but we're going to change them directly below here. + UpdateMainViewDimensions(renderer); + } + + view->pixel_w = (int) view->logical_dst_rect.w; + view->pixel_h = (int) view->logical_dst_rect.h; + UpdatePixelViewport(renderer, view); + UpdatePixelClipRect(renderer, view); +} + +bool SDL_SetRenderLogicalPresentation(SDL_Renderer *renderer, int w, int h, SDL_RendererLogicalPresentation mode) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + SDL_RenderViewState *view = renderer->view; + view->logical_presentation_mode = mode; + view->logical_w = w; + view->logical_h = h; + + UpdateLogicalPresentation(renderer); + + return true; +} + +bool SDL_GetRenderLogicalPresentation(SDL_Renderer *renderer, int *w, int *h, SDL_RendererLogicalPresentation *mode) +{ + #define SETVAL(ptr, val) if (ptr) { *ptr = val; } + + SETVAL(w, 0); + SETVAL(h, 0); + SETVAL(mode, SDL_LOGICAL_PRESENTATION_DISABLED); + + CHECK_RENDERER_MAGIC(renderer, false); + + const SDL_RenderViewState *view = renderer->view; + SETVAL(w, view->logical_w); + SETVAL(h, view->logical_h); + SETVAL(mode, view->logical_presentation_mode); + + #undef SETVAL + + return true; +} + +bool SDL_GetRenderLogicalPresentationRect(SDL_Renderer *renderer, SDL_FRect *rect) +{ + if (rect) { + SDL_zerop(rect); + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (rect) { + SDL_copyp(rect, &renderer->view->logical_dst_rect); + } + return true; +} + +static void SDL_RenderLogicalBorders(SDL_Renderer *renderer, const SDL_FRect *dst) +{ + const SDL_RenderViewState *view = renderer->view; + + if (dst->x > 0.0f || dst->y > 0.0f) { + SDL_BlendMode saved_blend_mode = renderer->blendMode; + SDL_FColor saved_color = renderer->color; + + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + SDL_SetRenderDrawColorFloat(renderer, 0.0f, 0.0f, 0.0f, 1.0f); + + if (dst->x > 0.0f) { + SDL_FRect rect; + + rect.x = 0.0f; + rect.y = 0.0f; + rect.w = dst->x; + rect.h = (float)view->pixel_h; + SDL_RenderFillRect(renderer, &rect); + + rect.x = dst->x + dst->w; + rect.w = (float)view->pixel_w - rect.x; + SDL_RenderFillRect(renderer, &rect); + } + + if (dst->y > 0.0f) { + SDL_FRect rect; + + rect.x = 0.0f; + rect.y = 0.0f; + rect.w = (float)view->pixel_w; + rect.h = dst->y; + SDL_RenderFillRect(renderer, &rect); + + rect.y = dst->y + dst->h; + rect.h = (float)view->pixel_h - rect.y; + SDL_RenderFillRect(renderer, &rect); + } + + SDL_SetRenderDrawBlendMode(renderer, saved_blend_mode); + SDL_SetRenderDrawColorFloat(renderer, saved_color.r, saved_color.g, saved_color.b, saved_color.a); + } +} + +static void SDL_RenderLogicalPresentation(SDL_Renderer *renderer) +{ + SDL_assert(renderer->view == &renderer->main_view); + + SDL_RenderViewState *view = &renderer->main_view; + const SDL_RendererLogicalPresentation mode = view->logical_presentation_mode; + if (mode == SDL_LOGICAL_PRESENTATION_LETTERBOX) { + // save off some state we're going to trample. + const int logical_w = view->logical_w; + const int logical_h = view->logical_h; + const float scale_x = view->scale.x; + const float scale_y = view->scale.y; + const bool clipping_enabled = view->clipping_enabled; + SDL_Rect orig_viewport, orig_cliprect; + const SDL_FRect logical_dst_rect = view->logical_dst_rect; + + SDL_copyp(&orig_viewport, &view->viewport); + if (clipping_enabled) { + SDL_copyp(&orig_cliprect, &view->clip_rect); + } + + // trample some state. + SDL_SetRenderLogicalPresentation(renderer, logical_w, logical_h, SDL_LOGICAL_PRESENTATION_DISABLED); + SDL_SetRenderViewport(renderer, NULL); + if (clipping_enabled) { + SDL_SetRenderClipRect(renderer, NULL); + } + SDL_SetRenderScale(renderer, 1.0f, 1.0f); + + // draw the borders. + SDL_RenderLogicalBorders(renderer, &logical_dst_rect); + + // now set everything back. + view->logical_presentation_mode = mode; + SDL_SetRenderViewport(renderer, &orig_viewport); + if (clipping_enabled) { + SDL_SetRenderClipRect(renderer, &orig_cliprect); + } + SDL_SetRenderScale(renderer, scale_x, scale_y); + + SDL_SetRenderLogicalPresentation(renderer, logical_w, logical_h, mode); + } +} + +static bool SDL_RenderVectorFromWindow(SDL_Renderer *renderer, float window_dx, float window_dy, float *dx, float *dy) +{ + // Convert from window coordinates to pixels within the window + window_dx *= renderer->dpi_scale.x; + window_dy *= renderer->dpi_scale.y; + + // Convert from pixels within the window to pixels within the view + const SDL_RenderViewState *view = &renderer->main_view; + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; + window_dx = (window_dx * src->w) / dst->w; + window_dy = (window_dy * src->h) / dst->h; + } + + window_dx /= view->scale.x; + window_dy /= view->scale.y; + + *dx = window_dx; + *dy = window_dy; + return true; +} + +bool SDL_RenderCoordinatesFromWindow(SDL_Renderer *renderer, float window_x, float window_y, float *x, float *y) +{ + float render_x, render_y; + + CHECK_RENDERER_MAGIC(renderer, false); + + // Convert from window coordinates to pixels within the window + render_x = window_x * renderer->dpi_scale.x; + render_y = window_y * renderer->dpi_scale.y; + + // Convert from pixels within the window to pixels within the view + const SDL_RenderViewState *view = &renderer->main_view; + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; + render_x = ((render_x - dst->x) * src->w) / dst->w; + render_y = ((render_y - dst->y) * src->h) / dst->h; + } + + render_x = (render_x / view->scale.x) - view->viewport.x; + render_y = (render_y / view->scale.y) - view->viewport.y; + + if (x) { + *x = render_x; + } + if (y) { + *y = render_y; + } + return true; +} + +bool SDL_RenderCoordinatesToWindow(SDL_Renderer *renderer, float x, float y, float *window_x, float *window_y) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + const SDL_RenderViewState *view = &renderer->main_view; + x = (view->viewport.x + x) * view->scale.x; + y = (view->viewport.y + y) * view->scale.y; + + // Convert from render coordinates to pixels within the window + if (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED) { + const SDL_FRect *src = &view->logical_src_rect; + const SDL_FRect *dst = &view->logical_dst_rect; + x = dst->x + ((x * dst->w) / src->w); + y = dst->y + ((y * dst->h) / src->h); + } + + // Convert from pixels within the window to window coordinates + x /= renderer->dpi_scale.x; + y /= renderer->dpi_scale.y; + + if (window_x) { + *window_x = x; + } + if (window_y) { + *window_y = y; + } + return true; +} + +bool SDL_ConvertEventToRenderCoordinates(SDL_Renderer *renderer, SDL_Event *event) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + if (event->type == SDL_EVENT_MOUSE_MOTION) { + SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->motion.x, event->motion.y, &event->motion.x, &event->motion.y); + SDL_RenderVectorFromWindow(renderer, event->motion.xrel, event->motion.yrel, &event->motion.xrel, &event->motion.yrel); + } + } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN || + event->type == SDL_EVENT_MOUSE_BUTTON_UP) { + SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->button.x, event->button.y, &event->button.x, &event->button.y); + } + } else if (event->type == SDL_EVENT_MOUSE_WHEEL) { + SDL_Window *window = SDL_GetWindowFromID(event->wheel.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->wheel.mouse_x, + event->wheel.mouse_y, + &event->wheel.mouse_x, + &event->wheel.mouse_y); + } + } else if (event->type == SDL_EVENT_FINGER_DOWN || + event->type == SDL_EVENT_FINGER_UP || + event->type == SDL_EVENT_FINGER_CANCELED || + event->type == SDL_EVENT_FINGER_MOTION) { + // FIXME: Are these events guaranteed to be window relative? + if (renderer->window) { + int w, h; + if (!SDL_GetWindowSize(renderer->window, &w, &h)) { + return false; + } + SDL_RenderCoordinatesFromWindow(renderer, event->tfinger.x * w, event->tfinger.y * h, &event->tfinger.x, &event->tfinger.y); + SDL_RenderVectorFromWindow(renderer, event->tfinger.dx * w, event->tfinger.dy * h, &event->tfinger.dx, &event->tfinger.dy); + } + } else if (event->type == SDL_EVENT_PEN_MOTION) { + SDL_Window *window = SDL_GetWindowFromID(event->pmotion.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->pmotion.x, event->pmotion.y, &event->pmotion.x, &event->pmotion.y); + } + } else if ((event->type == SDL_EVENT_PEN_DOWN) || (event->type == SDL_EVENT_PEN_UP)) { + SDL_Window *window = SDL_GetWindowFromID(event->ptouch.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->ptouch.x, event->ptouch.y, &event->ptouch.x, &event->ptouch.y); + } + } else if ((event->type == SDL_EVENT_PEN_BUTTON_DOWN) || (event->type == SDL_EVENT_PEN_BUTTON_UP)) { + SDL_Window *window = SDL_GetWindowFromID(event->pbutton.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->pbutton.x, event->pbutton.y, &event->pbutton.x, &event->pbutton.y); + } + } else if (event->type == SDL_EVENT_PEN_AXIS) { + SDL_Window *window = SDL_GetWindowFromID(event->paxis.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->paxis.x, event->paxis.y, &event->paxis.x, &event->paxis.y); + } + } else if (event->type == SDL_EVENT_DROP_POSITION || + event->type == SDL_EVENT_DROP_FILE || + event->type == SDL_EVENT_DROP_TEXT || + event->type == SDL_EVENT_DROP_COMPLETE) { + SDL_Window *window = SDL_GetWindowFromID(event->drop.windowID); + if (window == renderer->window) { + SDL_RenderCoordinatesFromWindow(renderer, event->drop.x, event->drop.y, &event->drop.x, &event->drop.y); + } + } + return true; +} + +bool SDL_SetRenderViewport(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + SDL_RenderViewState *view = renderer->view; + if (rect) { + if ((rect->w < 0) || (rect->h < 0)) { + return SDL_SetError("rect has a negative size"); + } + SDL_copyp(&view->viewport, rect); + } else { + view->viewport.x = view->viewport.y = 0; + view->viewport.w = view->viewport.h = -1; + } + UpdatePixelViewport(renderer, view); + + return QueueCmdSetViewport(renderer); +} + +bool SDL_GetRenderViewport(SDL_Renderer *renderer, SDL_Rect *rect) +{ + if (rect) { + SDL_zerop(rect); + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (rect) { + const SDL_RenderViewState *view = renderer->view; + rect->x = view->viewport.x; + rect->y = view->viewport.y; + if (view->viewport.w >= 0) { + rect->w = view->viewport.w; + } else { + rect->w = (int)SDL_ceilf(view->pixel_w / view->current_scale.x); + } + if (view->viewport.h >= 0) { + rect->h = view->viewport.h; + } else { + rect->h = (int)SDL_ceilf(view->pixel_h / view->current_scale.y); + } + } + return true; +} + +bool SDL_RenderViewportSet(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + const SDL_RenderViewState *view = renderer->view; + return (view->viewport.w >= 0 && view->viewport.h >= 0); +} + +static void GetRenderViewportSize(SDL_Renderer *renderer, SDL_FRect *rect) +{ + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + + rect->x = 0.0f; + rect->y = 0.0f; + + if (view->viewport.w >= 0) { + rect->w = (float)view->viewport.w; + } else { + rect->w = view->pixel_w / scale_x; + } + + if (view->viewport.h >= 0) { + rect->h = (float)view->viewport.h; + } else { + rect->h = view->pixel_h / scale_y; + } +} + +bool SDL_GetRenderSafeArea(SDL_Renderer *renderer, SDL_Rect *rect) +{ + if (rect) { + SDL_zerop(rect); + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (renderer->target || !renderer->window) { + // The entire viewport is safe for rendering + return SDL_GetRenderViewport(renderer, rect); + } + + if (rect) { + // Get the window safe rect + SDL_Rect safe; + if (!SDL_GetWindowSafeArea(renderer->window, &safe)) { + return false; + } + + // Convert the coordinates into the render space + float minx = (float)safe.x; + float miny = (float)safe.y; + float maxx = (float)safe.x + safe.w; + float maxy = (float)safe.y + safe.h; + if (!SDL_RenderCoordinatesFromWindow(renderer, minx, miny, &minx, &miny) || + !SDL_RenderCoordinatesFromWindow(renderer, maxx, maxy, &maxx, &maxy)) { + return false; + } + + rect->x = (int)SDL_ceilf(minx); + rect->y = (int)SDL_ceilf(miny); + rect->w = (int)SDL_ceilf(maxx - minx); + rect->h = (int)SDL_ceilf(maxy - miny); + + // Clip with the viewport + SDL_Rect viewport; + if (!SDL_GetRenderViewport(renderer, &viewport)) { + return false; + } + if (!SDL_GetRectIntersection(rect, &viewport, rect)) { + return SDL_SetError("No safe area within viewport"); + } + } + return true; +} + +bool SDL_SetRenderClipRect(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + CHECK_RENDERER_MAGIC(renderer, false) + + SDL_RenderViewState *view = renderer->view; + if (rect && rect->w >= 0 && rect->h >= 0) { + view->clipping_enabled = true; + SDL_copyp(&view->clip_rect, rect); + } else { + view->clipping_enabled = false; + SDL_zero(view->clip_rect); + } + UpdatePixelClipRect(renderer, view); + + return QueueCmdSetClipRect(renderer); +} + +bool SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect) +{ + if (rect) { + SDL_zerop(rect); + } + + CHECK_RENDERER_MAGIC(renderer, false) + + if (rect) { + SDL_copyp(rect, &renderer->view->clip_rect); + } + return true; +} + +bool SDL_RenderClipEnabled(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, false) + return renderer->view->clipping_enabled; +} + +bool SDL_SetRenderScale(SDL_Renderer *renderer, float scaleX, float scaleY) +{ + bool result = true; + + CHECK_RENDERER_MAGIC(renderer, false); + + SDL_RenderViewState *view = renderer->view; + + if ((view->scale.x == scaleX) && (view->scale.y == scaleY)) { + return true; + } + + view->scale.x = scaleX; + view->scale.y = scaleY; + view->current_scale.x = scaleX * view->logical_scale.x; + view->current_scale.y = scaleY * view->logical_scale.y; + UpdatePixelViewport(renderer, view); + UpdatePixelClipRect(renderer, view); + + // The scale affects the existing viewport and clip rectangle + result &= QueueCmdSetViewport(renderer); + result &= QueueCmdSetClipRect(renderer); + return result; +} + +bool SDL_GetRenderScale(SDL_Renderer *renderer, float *scaleX, float *scaleY) +{ + if (scaleX) { + *scaleX = 1.0f; + } + if (scaleY) { + *scaleY = 1.0f; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + const SDL_RenderViewState *view = renderer->view; + + if (scaleX) { + *scaleX = view->scale.x; + } + if (scaleY) { + *scaleY = view->scale.y; + } + return true; +} + +bool SDL_SetRenderDrawColor(SDL_Renderer *renderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a) +{ + const float fR = (float)r / 255.0f; + const float fG = (float)g / 255.0f; + const float fB = (float)b / 255.0f; + const float fA = (float)a / 255.0f; + + return SDL_SetRenderDrawColorFloat(renderer, fR, fG, fB, fA); +} + +bool SDL_SetRenderDrawColorFloat(SDL_Renderer *renderer, float r, float g, float b, float a) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + renderer->color.r = r; + renderer->color.g = g; + renderer->color.b = b; + renderer->color.a = a; + return true; +} + +bool SDL_GetRenderDrawColor(SDL_Renderer *renderer, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a) +{ + float fR, fG, fB, fA; + + if (!SDL_GetRenderDrawColorFloat(renderer, &fR, &fG, &fB, &fA)) { + if (r) { + *r = 0; + } + if (g) { + *g = 0; + } + if (b) { + *b = 0; + } + if (a) { + *a = 0; + } + return false; + } + + if (r) { + *r = (Uint8)(fR * 255.0f); + } + if (g) { + *g = (Uint8)(fG * 255.0f); + } + if (b) { + *b = (Uint8)(fB * 255.0f); + } + if (a) { + *a = (Uint8)(fA * 255.0f); + } + return true; +} + +bool SDL_GetRenderDrawColorFloat(SDL_Renderer *renderer, float *r, float *g, float *b, float *a) +{ + SDL_FColor color; + + if (r) { + *r = 0.0f; + } + if (g) { + *g = 0.0f; + } + if (b) { + *b = 0.0f; + } + if (a) { + *a = 0.0f; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + color = renderer->color; + + if (r) { + *r = color.r; + } + if (g) { + *g = color.g; + } + if (b) { + *b = color.b; + } + if (a) { + *a = color.a; + } + return true; +} + +bool SDL_SetRenderColorScale(SDL_Renderer *renderer, float scale) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + renderer->desired_color_scale = scale; + UpdateColorScale(renderer); + return true; +} + +bool SDL_GetRenderColorScale(SDL_Renderer *renderer, float *scale) +{ + if (scale) { + *scale = 1.0f; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (scale) { + *scale = renderer->desired_color_scale; + } + return true; +} + +bool SDL_SetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + if (blendMode == SDL_BLENDMODE_INVALID) { + return SDL_InvalidParamError("blendMode"); + } + + if (blendMode == SDL_BLENDMODE_INVALID) { + return SDL_InvalidParamError("blendMode"); + } + + if (!IsSupportedBlendMode(renderer, blendMode)) { + return SDL_Unsupported(); + } + + renderer->blendMode = blendMode; + return true; +} + +bool SDL_GetRenderDrawBlendMode(SDL_Renderer *renderer, SDL_BlendMode *blendMode) +{ + if (blendMode) { + *blendMode = SDL_BLENDMODE_INVALID; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (blendMode) { + *blendMode = renderer->blendMode; + } + return true; +} + +bool SDL_RenderClear(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + return QueueCmdClear(renderer); +} + +bool SDL_RenderPoint(SDL_Renderer *renderer, float x, float y) +{ + SDL_FPoint fpoint; + fpoint.x = x; + fpoint.y = y; + return SDL_RenderPoints(renderer, &fpoint, 1); +} + +static bool RenderPointsWithRects(SDL_Renderer *renderer, const SDL_FPoint *fpoints, const int count) +{ + bool result; + bool isstack; + SDL_FRect *frects; + int i; + + if (count < 1) { + return true; + } + + frects = SDL_small_alloc(SDL_FRect, count, &isstack); + if (!frects) { + return false; + } + + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + for (i = 0; i < count; ++i) { + frects[i].x = fpoints[i].x * scale_x; + frects[i].y = fpoints[i].y * scale_y; + frects[i].w = scale_x; + frects[i].h = scale_y; + } + + result = QueueCmdFillRects(renderer, frects, count); + + SDL_small_free(frects, isstack); + + return result; +} + +bool SDL_RenderPoints(SDL_Renderer *renderer, const SDL_FPoint *points, int count) +{ + bool result; + + CHECK_RENDERER_MAGIC(renderer, false); + + if (!points) { + return SDL_InvalidParamError("SDL_RenderPoints(): points"); + } + if (count < 1) { + return true; + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + const SDL_RenderViewState *view = renderer->view; + if ((view->current_scale.x != 1.0f) || (view->current_scale.y != 1.0f)) { + result = RenderPointsWithRects(renderer, points, count); + } else { + result = QueueCmdDrawPoints(renderer, points, count); + } + return result; +} + +bool SDL_RenderLine(SDL_Renderer *renderer, float x1, float y1, float x2, float y2) +{ + SDL_FPoint points[2]; + points[0].x = x1; + points[0].y = y1; + points[1].x = x2; + points[1].y = y2; + return SDL_RenderLines(renderer, points, 2); +} + +static bool RenderLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x2, int y2, bool draw_last) +{ + const SDL_RenderViewState *view = renderer->view; + const int MAX_PIXELS = SDL_max(view->pixel_w, view->pixel_h) * 4; + int i, deltax, deltay, numpixels; + int d, dinc1, dinc2; + int x, xinc1, xinc2; + int y, yinc1, yinc2; + bool result; + bool isstack; + SDL_FPoint *points; + SDL_Rect viewport; + + /* the backend might clip this further to the clipping rect, but we + just want a basic safety against generating millions of points for + massive lines. */ + viewport = view->pixel_viewport; + viewport.x = 0; + viewport.y = 0; + if (!SDL_GetRectAndLineIntersection(&viewport, &x1, &y1, &x2, &y2)) { + return true; + } + + deltax = SDL_abs(x2 - x1); + deltay = SDL_abs(y2 - y1); + + if (deltax >= deltay) { + numpixels = deltax + 1; + d = (2 * deltay) - deltax; + dinc1 = deltay * 2; + dinc2 = (deltay - deltax) * 2; + xinc1 = 1; + xinc2 = 1; + yinc1 = 0; + yinc2 = 1; + } else { + numpixels = deltay + 1; + d = (2 * deltax) - deltay; + dinc1 = deltax * 2; + dinc2 = (deltax - deltay) * 2; + xinc1 = 0; + xinc2 = 1; + yinc1 = 1; + yinc2 = 1; + } + + if (x1 > x2) { + xinc1 = -xinc1; + xinc2 = -xinc2; + } + if (y1 > y2) { + yinc1 = -yinc1; + yinc2 = -yinc2; + } + + x = x1; + y = y1; + + if (!draw_last) { + --numpixels; + } + + if (numpixels > MAX_PIXELS) { + return SDL_SetError("Line too long (tried to draw %d pixels, max %d)", numpixels, MAX_PIXELS); + } + + points = SDL_small_alloc(SDL_FPoint, numpixels, &isstack); + if (!points) { + return false; + } + for (i = 0; i < numpixels; ++i) { + points[i].x = (float)x; + points[i].y = (float)y; + + if (d < 0) { + d += dinc1; + x += xinc1; + y += yinc1; + } else { + d += dinc2; + x += xinc2; + y += yinc2; + } + } + + if ((view->current_scale.x != 1.0f) || (view->current_scale.y != 1.0f)) { + result = RenderPointsWithRects(renderer, points, numpixels); + } else { + result = QueueCmdDrawPoints(renderer, points, numpixels); + } + + SDL_small_free(points, isstack); + + return result; +} + +static bool RenderLinesWithRectsF(SDL_Renderer *renderer, const SDL_FPoint *points, const int count) +{ + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + SDL_FRect *frect; + SDL_FRect *frects; + int i, nrects = 0; + bool result = true; + bool isstack; + bool drew_line = false; + bool draw_last = false; + + frects = SDL_small_alloc(SDL_FRect, count - 1, &isstack); + if (!frects) { + return false; + } + + for (i = 0; i < count - 1; ++i) { + bool same_x = (points[i].x == points[i + 1].x); + bool same_y = (points[i].y == points[i + 1].y); + + if (i == (count - 2)) { + if (!drew_line || points[i + 1].x != points[0].x || points[i + 1].y != points[0].y) { + draw_last = true; + } + } else { + if (same_x && same_y) { + continue; + } + } + if (same_x) { + const float minY = SDL_min(points[i].y, points[i + 1].y); + const float maxY = SDL_max(points[i].y, points[i + 1].y); + + frect = &frects[nrects++]; + frect->x = points[i].x * scale_x; + frect->y = minY * scale_y; + frect->w = scale_x; + frect->h = (maxY - minY + draw_last) * scale_y; + if (!draw_last && points[i + 1].y < points[i].y) { + frect->y += scale_y; + } + } else if (same_y) { + const float minX = SDL_min(points[i].x, points[i + 1].x); + const float maxX = SDL_max(points[i].x, points[i + 1].x); + + frect = &frects[nrects++]; + frect->x = minX * scale_x; + frect->y = points[i].y * scale_y; + frect->w = (maxX - minX + draw_last) * scale_x; + frect->h = scale_y; + if (!draw_last && points[i + 1].x < points[i].x) { + frect->x += scale_x; + } + } else { + result &= RenderLineBresenham(renderer, (int)SDL_roundf(points[i].x), (int)SDL_roundf(points[i].y), + (int)SDL_roundf(points[i + 1].x), (int)SDL_roundf(points[i + 1].y), draw_last); + } + drew_line = true; + } + + if (nrects) { + result &= QueueCmdFillRects(renderer, frects, nrects); + } + + SDL_small_free(frects, isstack); + + return result; +} + +bool SDL_RenderLines(SDL_Renderer *renderer, const SDL_FPoint *points, int count) +{ + bool result = true; + + CHECK_RENDERER_MAGIC(renderer, false); + + if (!points) { + return SDL_InvalidParamError("SDL_RenderLines(): points"); + } + if (count < 2) { + return true; + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + SDL_RenderViewState *view = renderer->view; + const bool islogical = ((view == &renderer->main_view) && (view->logical_presentation_mode != SDL_LOGICAL_PRESENTATION_DISABLED)); + + if (islogical || (renderer->line_method == SDL_RENDERLINEMETHOD_GEOMETRY)) { + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + bool isstack1; + bool isstack2; + float *xy = SDL_small_alloc(float, 4 * 2 * count, &isstack1); + int *indices = SDL_small_alloc(int, (4) * 3 * (count - 1) + (2) * 3 * (count), &isstack2); + + if (xy && indices) { + int i; + float *ptr_xy = xy; + int *ptr_indices = indices; + const int xy_stride = 2 * sizeof(float); + int num_vertices = 4 * count; + int num_indices = 0; + const int size_indices = 4; + int cur_index = -4; + const int is_looping = (points[0].x == points[count - 1].x && points[0].y == points[count - 1].y); + SDL_FPoint p; // previous point + p.x = p.y = 0.0f; + /* p q + + 0----1------ 4----5 + | \ |``\ | \ | + | \ | ` `\| \ | + 3----2-------7----6 + */ + for (i = 0; i < count; ++i) { + SDL_FPoint q = points[i]; // current point + + q.x *= scale_x; + q.y *= scale_y; + + *ptr_xy++ = q.x; + *ptr_xy++ = q.y; + *ptr_xy++ = q.x + scale_x; + *ptr_xy++ = q.y; + *ptr_xy++ = q.x + scale_x; + *ptr_xy++ = q.y + scale_y; + *ptr_xy++ = q.x; + *ptr_xy++ = q.y + scale_y; + +#define ADD_TRIANGLE(i1, i2, i3) \ + *ptr_indices++ = cur_index + (i1); \ + *ptr_indices++ = cur_index + (i2); \ + *ptr_indices++ = cur_index + (i3); \ + num_indices += 3; + + // closed polyline, don´t draw twice the point + if (i || is_looping == 0) { + ADD_TRIANGLE(4, 5, 6) + ADD_TRIANGLE(4, 6, 7) + } + + // first point only, no segment + if (i == 0) { + p = q; + cur_index += 4; + continue; + } + + // draw segment + if (p.y == q.y) { + if (p.x < q.x) { + ADD_TRIANGLE(1, 4, 7) + ADD_TRIANGLE(1, 7, 2) + } else { + ADD_TRIANGLE(5, 0, 3) + ADD_TRIANGLE(5, 3, 6) + } + } else if (p.x == q.x) { + if (p.y < q.y) { + ADD_TRIANGLE(2, 5, 4) + ADD_TRIANGLE(2, 4, 3) + } else { + ADD_TRIANGLE(6, 1, 0) + ADD_TRIANGLE(6, 0, 7) + } + } else { + if (p.y < q.y) { + if (p.x < q.x) { + ADD_TRIANGLE(1, 5, 4) + ADD_TRIANGLE(1, 4, 2) + ADD_TRIANGLE(2, 4, 7) + ADD_TRIANGLE(2, 7, 3) + } else { + ADD_TRIANGLE(4, 0, 5) + ADD_TRIANGLE(5, 0, 3) + ADD_TRIANGLE(5, 3, 6) + ADD_TRIANGLE(6, 3, 2) + } + } else { + if (p.x < q.x) { + ADD_TRIANGLE(0, 4, 7) + ADD_TRIANGLE(0, 7, 1) + ADD_TRIANGLE(1, 7, 6) + ADD_TRIANGLE(1, 6, 2) + } else { + ADD_TRIANGLE(6, 5, 1) + ADD_TRIANGLE(6, 1, 0) + ADD_TRIANGLE(7, 6, 0) + ADD_TRIANGLE(7, 0, 3) + } + } + } + + p = q; + cur_index += 4; + } + + result = QueueCmdGeometry(renderer, NULL, + xy, xy_stride, &renderer->color, 0 /* color_stride */, NULL, 0, + num_vertices, indices, num_indices, size_indices, + 1.0f, 1.0f, SDL_TEXTURE_ADDRESS_CLAMP); + } + + SDL_small_free(xy, isstack1); + SDL_small_free(indices, isstack2); + + } else if (renderer->line_method == SDL_RENDERLINEMETHOD_POINTS) { + result = RenderLinesWithRectsF(renderer, points, count); + } else if (view->scale.x != 1.0f || view->scale.y != 1.0f) { /* we checked for logical scale elsewhere. */ + result = RenderLinesWithRectsF(renderer, points, count); + } else { + result = QueueCmdDrawLines(renderer, points, count); + } + + return result; +} + +bool SDL_RenderRect(SDL_Renderer *renderer, const SDL_FRect *rect) +{ + SDL_FRect frect; + SDL_FPoint points[5]; + + CHECK_RENDERER_MAGIC(renderer, false); + + // If 'rect' == NULL, then outline the whole surface + if (!rect) { + GetRenderViewportSize(renderer, &frect); + rect = &frect; + } + + points[0].x = rect->x; + points[0].y = rect->y; + points[1].x = rect->x + rect->w - 1; + points[1].y = rect->y; + points[2].x = rect->x + rect->w - 1; + points[2].y = rect->y + rect->h - 1; + points[3].x = rect->x; + points[3].y = rect->y + rect->h - 1; + points[4].x = rect->x; + points[4].y = rect->y; + return SDL_RenderLines(renderer, points, 5); +} + +bool SDL_RenderRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count) +{ + int i; + + CHECK_RENDERER_MAGIC(renderer, false); + + if (!rects) { + return SDL_InvalidParamError("SDL_RenderRects(): rects"); + } + if (count < 1) { + return true; + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + for (i = 0; i < count; ++i) { + if (!SDL_RenderRect(renderer, &rects[i])) { + return false; + } + } + return true; +} + +bool SDL_RenderFillRect(SDL_Renderer *renderer, const SDL_FRect *rect) +{ + SDL_FRect frect; + + CHECK_RENDERER_MAGIC(renderer, false); + + // If 'rect' == NULL, then fill the whole surface + if (!rect) { + GetRenderViewportSize(renderer, &frect); + rect = &frect; + } + return SDL_RenderFillRects(renderer, rect, 1); +} + +bool SDL_RenderFillRects(SDL_Renderer *renderer, const SDL_FRect *rects, int count) +{ + SDL_FRect *frects; + int i; + bool result; + bool isstack; + + CHECK_RENDERER_MAGIC(renderer, false); + + if (!rects) { + return SDL_InvalidParamError("SDL_RenderFillRects(): rects"); + } + if (count < 1) { + return true; + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + frects = SDL_small_alloc(SDL_FRect, count, &isstack); + if (!frects) { + return false; + } + + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + for (i = 0; i < count; ++i) { + frects[i].x = rects[i].x * scale_x; + frects[i].y = rects[i].y * scale_y; + frects[i].w = rects[i].w * scale_x; + frects[i].h = rects[i].h * scale_y; + } + + result = QueueCmdFillRects(renderer, frects, count); + + SDL_small_free(frects, isstack); + + return result; +} + +static bool SDL_RenderTextureInternal(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect) +{ + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + const bool use_rendergeometry = (!renderer->QueueCopy); + bool result; + + if (use_rendergeometry) { + float xy[8]; + const int xy_stride = 2 * sizeof(float); + float uv[8]; + const int uv_stride = 2 * sizeof(float); + const int num_vertices = 4; + const int *indices = rect_index_order; + const int num_indices = 6; + const int size_indices = 4; + float minu, minv, maxu, maxv; + float minx, miny, maxx, maxy; + + minu = srcrect->x / texture->w; + minv = srcrect->y / texture->h; + maxu = (srcrect->x + srcrect->w) / texture->w; + maxv = (srcrect->y + srcrect->h) / texture->h; + + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; + + uv[0] = minu; + uv[1] = minv; + uv[2] = maxu; + uv[3] = minv; + uv[4] = maxu; + uv[5] = maxv; + uv[6] = minu; + uv[7] = maxv; + + xy[0] = minx; + xy[1] = miny; + xy[2] = maxx; + xy[3] = miny; + xy[4] = maxx; + xy[5] = maxy; + xy[6] = minx; + xy[7] = maxy; + + result = QueueCmdGeometry(renderer, texture, + xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + } else { + const SDL_FRect rect = { dstrect->x * scale_x, dstrect->y * scale_y, dstrect->w * scale_x, dstrect->h * scale_y }; + result = QueueCmdCopy(renderer, texture, srcrect, &rect); + } + return result; +} + +bool SDL_RenderTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, const SDL_FRect *dstrect) +{ + CHECK_RENDERER_MAGIC(renderer, false); + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + SDL_FRect real_srcrect; + real_srcrect.x = 0.0f; + real_srcrect.y = 0.0f; + real_srcrect.w = (float)texture->w; + real_srcrect.h = (float)texture->h; + if (srcrect) { + if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect) || + real_srcrect.w == 0.0f || real_srcrect.h == 0.0f) { + return true; + } + } + + SDL_FRect full_dstrect; + if (!dstrect) { + GetRenderViewportSize(renderer, &full_dstrect); + dstrect = &full_dstrect; + } + + if (texture->native) { + texture = texture->native; + } + + texture->last_command_generation = renderer->render_command_generation; + + return SDL_RenderTextureInternal(renderer, texture, &real_srcrect, dstrect); +} + +bool SDL_RenderTextureAffine(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_FRect *srcrect, const SDL_FPoint *origin, const SDL_FPoint *right, const SDL_FPoint *down) +{ + SDL_FRect real_srcrect; + SDL_FRect real_dstrect; + bool result; + + CHECK_RENDERER_MAGIC(renderer, false); + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + if (!renderer->QueueCopyEx && !renderer->QueueGeometry) { + return SDL_SetError("Renderer does not support RenderCopyEx"); + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + real_srcrect.x = 0.0f; + real_srcrect.y = 0.0f; + real_srcrect.w = (float)texture->w; + real_srcrect.h = (float)texture->h; + if (srcrect) { + if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) { + return true; + } + } + + GetRenderViewportSize(renderer, &real_dstrect); + + if (texture->native) { + texture = texture->native; + } + + texture->last_command_generation = renderer->render_command_generation; + + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + + { + float xy[8]; + const int xy_stride = 2 * sizeof(float); + float uv[8]; + const int uv_stride = 2 * sizeof(float); + const int num_vertices = 4; + const int *indices = rect_index_order; + const int num_indices = 6; + const int size_indices = 4; + + float minu = real_srcrect.x / texture->w; + float minv = real_srcrect.y / texture->h; + float maxu = (real_srcrect.x + real_srcrect.w) / texture->w; + float maxv = (real_srcrect.y + real_srcrect.h) / texture->h; + + uv[0] = minu; + uv[1] = minv; + uv[2] = maxu; + uv[3] = minv; + uv[4] = maxu; + uv[5] = maxv; + uv[6] = minu; + uv[7] = maxv; + + // (minx, miny) + if (origin) { + xy[0] = origin->x; + xy[1] = origin->y; + } else { + xy[0] = real_dstrect.x; + xy[1] = real_dstrect.y; + } + + // (maxx, miny) + if (right) { + xy[2] = right->x; + xy[3] = right->y; + } else { + xy[2] = real_dstrect.x + real_dstrect.w; + xy[3] = real_dstrect.y; + } + + // (minx, maxy) + if (down) { + xy[6] = down->x; + xy[7] = down->y; + } else { + xy[6] = real_dstrect.x; + xy[7] = real_dstrect.y + real_dstrect.h; + } + + // (maxx, maxy) + if (origin || right || down) { + xy[4] = xy[2] + xy[6] - xy[0]; + xy[5] = xy[3] + xy[7] - xy[1]; + } else { + xy[4] = real_dstrect.x + real_dstrect.w; + xy[5] = real_dstrect.y + real_dstrect.h; + } + + result = QueueCmdGeometry( + renderer, texture, + xy, xy_stride, + &texture->color, 0 /* color_stride */, + uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP + ); + } + return result; +} + +bool SDL_RenderTextureRotated(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_FRect *srcrect, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip) +{ + SDL_FRect real_srcrect; + SDL_FPoint real_center; + bool result; + + if (flip == SDL_FLIP_NONE && (int)(angle / 360) == angle / 360) { // fast path when we don't need rotation or flipping + return SDL_RenderTexture(renderer, texture, srcrect, dstrect); + } + + CHECK_RENDERER_MAGIC(renderer, false); + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + if (!renderer->QueueCopyEx && !renderer->QueueGeometry) { + return SDL_SetError("Renderer does not support RenderCopyEx"); + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + real_srcrect.x = 0.0f; + real_srcrect.y = 0.0f; + real_srcrect.w = (float)texture->w; + real_srcrect.h = (float)texture->h; + if (srcrect) { + if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) { + return true; + } + } + + // We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? + SDL_FRect full_dstrect; + if (!dstrect) { + GetRenderViewportSize(renderer, &full_dstrect); + dstrect = &full_dstrect; + } + + if (texture->native) { + texture = texture->native; + } + + if (center) { + real_center = *center; + } else { + real_center.x = dstrect->w / 2.0f; + real_center.y = dstrect->h / 2.0f; + } + + texture->last_command_generation = renderer->render_command_generation; + + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + + const bool use_rendergeometry = (!renderer->QueueCopyEx); + if (use_rendergeometry) { + float xy[8]; + const int xy_stride = 2 * sizeof(float); + float uv[8]; + const int uv_stride = 2 * sizeof(float); + const int num_vertices = 4; + const int *indices = rect_index_order; + const int num_indices = 6; + const int size_indices = 4; + float minu, minv, maxu, maxv; + float minx, miny, maxx, maxy; + float centerx, centery; + + float s_minx, s_miny, s_maxx, s_maxy; + float c_minx, c_miny, c_maxx, c_maxy; + + const float radian_angle = (float)((SDL_PI_D * angle) / 180.0); + const float s = SDL_sinf(radian_angle); + const float c = SDL_cosf(radian_angle); + + minu = real_srcrect.x / texture->w; + minv = real_srcrect.y / texture->h; + maxu = (real_srcrect.x + real_srcrect.w) / texture->w; + maxv = (real_srcrect.y + real_srcrect.h) / texture->h; + + centerx = real_center.x + dstrect->x; + centery = real_center.y + dstrect->y; + + if (flip & SDL_FLIP_HORIZONTAL) { + minx = dstrect->x + dstrect->w; + maxx = dstrect->x; + } else { + minx = dstrect->x; + maxx = dstrect->x + dstrect->w; + } + + if (flip & SDL_FLIP_VERTICAL) { + miny = dstrect->y + dstrect->h; + maxy = dstrect->y; + } else { + miny = dstrect->y; + maxy = dstrect->y + dstrect->h; + } + + uv[0] = minu; + uv[1] = minv; + uv[2] = maxu; + uv[3] = minv; + uv[4] = maxu; + uv[5] = maxv; + uv[6] = minu; + uv[7] = maxv; + + /* apply rotation with 2x2 matrix ( c -s ) + * ( s c ) */ + s_minx = s * (minx - centerx); + s_miny = s * (miny - centery); + s_maxx = s * (maxx - centerx); + s_maxy = s * (maxy - centery); + c_minx = c * (minx - centerx); + c_miny = c * (miny - centery); + c_maxx = c * (maxx - centerx); + c_maxy = c * (maxy - centery); + + // (minx, miny) + xy[0] = (c_minx - s_miny) + centerx; + xy[1] = (s_minx + c_miny) + centery; + // (maxx, miny) + xy[2] = (c_maxx - s_miny) + centerx; + xy[3] = (s_maxx + c_miny) + centery; + // (maxx, maxy) + xy[4] = (c_maxx - s_maxy) + centerx; + xy[5] = (s_maxx + c_maxy) + centery; + // (minx, maxy) + xy[6] = (c_minx - s_maxy) + centerx; + xy[7] = (s_minx + c_maxy) + centery; + + result = QueueCmdGeometry(renderer, texture, + xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + } else { + result = QueueCmdCopyEx(renderer, texture, &real_srcrect, dstrect, angle, &real_center, flip, scale_x, scale_y); + } + return result; +} + +static bool SDL_RenderTextureTiled_Wrap(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) +{ + float xy[8]; + const int xy_stride = 2 * sizeof(float); + float uv[8]; + const int uv_stride = 2 * sizeof(float); + const int num_vertices = 4; + const int *indices = rect_index_order; + const int num_indices = 6; + const int size_indices = 4; + float minu, minv, maxu, maxv; + float minx, miny, maxx, maxy; + + minu = 0.0f; + minv = 0.0f; + maxu = dstrect->w / (srcrect->w * scale); + maxv = dstrect->h / (srcrect->h * scale); + + minx = dstrect->x; + miny = dstrect->y; + maxx = dstrect->x + dstrect->w; + maxy = dstrect->y + dstrect->h; + + uv[0] = minu; + uv[1] = minv; + uv[2] = maxu; + uv[3] = minv; + uv[4] = maxu; + uv[5] = maxv; + uv[6] = minu; + uv[7] = maxv; + + xy[0] = minx; + xy[1] = miny; + xy[2] = maxx; + xy[3] = miny; + xy[4] = maxx; + xy[5] = maxy; + xy[6] = minx; + xy[7] = maxy; + + const SDL_RenderViewState *view = renderer->view; + return QueueCmdGeometry(renderer, texture, + xy, xy_stride, &texture->color, 0 /* color_stride */, uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + view->current_scale.x, view->current_scale.y, SDL_TEXTURE_ADDRESS_WRAP); +} + +static bool SDL_RenderTextureTiled_Iterate(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) +{ + float tile_width = srcrect->w * scale; + float tile_height = srcrect->h * scale; + float float_rows, float_cols; + float remaining_w = SDL_modff(dstrect->w / tile_width, &float_cols); + float remaining_h = SDL_modff(dstrect->h / tile_height, &float_rows); + float remaining_src_w = remaining_w * srcrect->w; + float remaining_src_h = remaining_h * srcrect->h; + float remaining_dst_w = remaining_w * tile_width; + float remaining_dst_h = remaining_h * tile_height; + int rows = (int)float_rows; + int cols = (int)float_cols; + SDL_FRect curr_src, curr_dst; + + SDL_copyp(&curr_src, srcrect); + curr_dst.y = dstrect->y; + curr_dst.w = tile_width; + curr_dst.h = tile_height; + for (int y = 0; y < rows; ++y) { + curr_dst.x = dstrect->x; + for (int x = 0; x < cols; ++x) { + if (!SDL_RenderTextureInternal(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + curr_dst.x += curr_dst.w; + } + if (remaining_dst_w > 0.0f) { + curr_src.w = remaining_src_w; + curr_dst.w = remaining_dst_w; + if (!SDL_RenderTextureInternal(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + curr_src.w = srcrect->w; + curr_dst.w = tile_width; + } + curr_dst.y += curr_dst.h; + } + if (remaining_dst_h > 0.0f) { + curr_src.h = remaining_src_h; + curr_dst.h = remaining_dst_h; + curr_dst.x = dstrect->x; + for (int x = 0; x < cols; ++x) { + if (!SDL_RenderTextureInternal(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + curr_dst.x += curr_dst.w; + } + if (remaining_dst_w > 0.0f) { + curr_src.w = remaining_src_w; + curr_dst.w = remaining_dst_w; + if (!SDL_RenderTextureInternal(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + } + } + return true; +} + +bool SDL_RenderTextureTiled(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float scale, const SDL_FRect *dstrect) +{ + SDL_FRect real_srcrect; + + CHECK_RENDERER_MAGIC(renderer, false); + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + + if (scale <= 0.0f) { + return SDL_InvalidParamError("scale"); + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + real_srcrect.x = 0.0f; + real_srcrect.y = 0.0f; + real_srcrect.w = (float)texture->w; + real_srcrect.h = (float)texture->h; + if (srcrect) { + if (!SDL_GetRectIntersectionFloat(srcrect, &real_srcrect, &real_srcrect)) { + return true; + } + } + + SDL_FRect full_dstrect; + if (!dstrect) { + GetRenderViewportSize(renderer, &full_dstrect); + dstrect = &full_dstrect; + } + + if (texture->native) { + texture = texture->native; + } + + texture->last_command_generation = renderer->render_command_generation; + + // See if we can use geometry with repeating texture coordinates + if (!renderer->software && + (!srcrect || + (real_srcrect.x == 0.0f && real_srcrect.y == 0.0f && + real_srcrect.w == (float)texture->w && real_srcrect.h == (float)texture->h))) { + return SDL_RenderTextureTiled_Wrap(renderer, texture, &real_srcrect, scale, dstrect); + } else { + return SDL_RenderTextureTiled_Iterate(renderer, texture, &real_srcrect, scale, dstrect); + } +} + +bool SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float left_width, float right_width, float top_height, float bottom_height, float scale, const SDL_FRect *dstrect) +{ + SDL_FRect full_src, full_dst; + SDL_FRect curr_src, curr_dst; + float dst_left_width; + float dst_right_width; + float dst_top_height; + float dst_bottom_height; + + CHECK_RENDERER_MAGIC(renderer, false); + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + + if (!srcrect) { + full_src.x = 0; + full_src.y = 0; + full_src.w = (float)texture->w; + full_src.h = (float)texture->h; + srcrect = &full_src; + } + + if (!dstrect) { + GetRenderViewportSize(renderer, &full_dst); + dstrect = &full_dst; + } + + if (scale <= 0.0f || scale == 1.0f) { + dst_left_width = SDL_ceilf(left_width); + dst_right_width = SDL_ceilf(right_width); + dst_top_height = SDL_ceilf(top_height); + dst_bottom_height = SDL_ceilf(bottom_height); + } else { + dst_left_width = SDL_ceilf(left_width * scale); + dst_right_width = SDL_ceilf(right_width * scale); + dst_top_height = SDL_ceilf(top_height * scale); + dst_bottom_height = SDL_ceilf(bottom_height * scale); + } + + // Center + curr_src.x = srcrect->x + left_width; + curr_src.y = srcrect->y + top_height; + curr_src.w = srcrect->w - left_width - right_width; + curr_src.h = srcrect->h - top_height - bottom_height; + curr_dst.x = dstrect->x + dst_left_width; + curr_dst.y = dstrect->y + dst_top_height; + curr_dst.w = dstrect->w - dst_left_width - dst_right_width; + curr_dst.h = dstrect->h - dst_top_height - dst_bottom_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Upper-left corner + curr_src.x = srcrect->x; + curr_src.y = srcrect->y; + curr_src.w = left_width; + curr_src.h = top_height; + curr_dst.x = dstrect->x; + curr_dst.y = dstrect->y; + curr_dst.w = dst_left_width; + curr_dst.h = dst_top_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Upper-right corner + curr_src.x = srcrect->x + srcrect->w - right_width; + curr_src.w = right_width; + curr_dst.x = dstrect->x + dstrect->w - dst_right_width; + curr_dst.w = dst_right_width; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Lower-right corner + curr_src.y = srcrect->y + srcrect->h - bottom_height; + curr_src.h = bottom_height; + curr_dst.y = dstrect->y + dstrect->h - dst_bottom_height; + curr_dst.h = dst_bottom_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Lower-left corner + curr_src.x = srcrect->x; + curr_src.w = left_width; + curr_dst.x = dstrect->x; + curr_dst.w = dst_left_width; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Left + curr_src.y = srcrect->y + top_height; + curr_src.h = srcrect->h - top_height - bottom_height; + curr_dst.y = dstrect->y + dst_top_height; + curr_dst.h = dstrect->h - dst_top_height - dst_bottom_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Right + curr_src.x = srcrect->x + srcrect->w - right_width; + curr_src.w = right_width; + curr_dst.x = dstrect->x + dstrect->w - dst_right_width; + curr_dst.w = dst_right_width; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Top + curr_src.x = srcrect->x + left_width; + curr_src.y = srcrect->y; + curr_src.w = srcrect->w - left_width - right_width; + curr_src.h = top_height; + curr_dst.x = dstrect->x + dst_left_width; + curr_dst.y = dstrect->y; + curr_dst.w = dstrect->w - dst_left_width - dst_right_width; + curr_dst.h = dst_top_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + // Bottom + curr_src.y = srcrect->y + srcrect->h - bottom_height; + curr_src.h = bottom_height; + curr_dst.y = dstrect->y + dstrect->h - dst_bottom_height; + curr_dst.h = dst_bottom_height; + if (!SDL_RenderTexture(renderer, texture, &curr_src, &curr_dst)) { + return false; + } + + return true; +} + +bool SDL_RenderGeometry(SDL_Renderer *renderer, + SDL_Texture *texture, + const SDL_Vertex *vertices, int num_vertices, + const int *indices, int num_indices) +{ + if (vertices) { + const float *xy = &vertices->position.x; + int xy_stride = sizeof(SDL_Vertex); + const SDL_FColor *color = &vertices->color; + int color_stride = sizeof(SDL_Vertex); + const float *uv = &vertices->tex_coord.x; + int uv_stride = sizeof(SDL_Vertex); + int size_indices = 4; + return SDL_RenderGeometryRaw(renderer, texture, xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, indices, num_indices, size_indices); + } else { + return SDL_InvalidParamError("vertices"); + } +} + +#ifdef SDL_VIDEO_RENDER_SW +static int remap_one_indice( + int prev, + int k, + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride) +{ + const float *xy0_, *xy1_, *uv0_, *uv1_; + const SDL_FColor *col0_, *col1_; + xy0_ = (const float *)((const char *)xy + prev * xy_stride); + xy1_ = (const float *)((const char *)xy + k * xy_stride); + if (xy0_[0] != xy1_[0]) { + return k; + } + if (xy0_[1] != xy1_[1]) { + return k; + } + if (texture) { + uv0_ = (const float *)((const char *)uv + prev * uv_stride); + uv1_ = (const float *)((const char *)uv + k * uv_stride); + if (uv0_[0] != uv1_[0]) { + return k; + } + if (uv0_[1] != uv1_[1]) { + return k; + } + } + col0_ = (const SDL_FColor *)((const char *)color + prev * color_stride); + col1_ = (const SDL_FColor *)((const char *)color + k * color_stride); + + if (SDL_memcmp(col0_, col1_, sizeof(*col0_)) != 0) { + return k; + } + + return prev; +} + +static int remap_indices( + int prev[3], + int k, + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride) +{ + int i; + if (prev[0] == -1) { + return k; + } + + for (i = 0; i < 3; i++) { + int new_k = remap_one_indice(prev[i], k, texture, xy, xy_stride, color, color_stride, uv, uv_stride); + if (new_k != k) { + return new_k; + } + } + return k; +} + +#define DEBUG_SW_RENDER_GEOMETRY 0 +// For the software renderer, try to reinterpret triangles as SDL_Rect +static bool SDLCALL SDL_SW_RenderGeometryRaw(SDL_Renderer *renderer, + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices) +{ + int i; + bool result = true; + int count = indices ? num_indices : num_vertices; + int prev[3]; // Previous triangle vertex indices + float texw = 0.0f, texh = 0.0f; + SDL_BlendMode blendMode = SDL_BLENDMODE_NONE; + float r = 0, g = 0, b = 0, a = 0; + const SDL_RenderViewState *view = renderer->view; + const float scale_x = view->current_scale.x; + const float scale_y = view->current_scale.y; + + // Save + SDL_GetRenderDrawBlendMode(renderer, &blendMode); + SDL_GetRenderDrawColorFloat(renderer, &r, &g, &b, &a); + + if (texture) { + SDL_GetTextureSize(texture, &texw, &texh); + } + + prev[0] = -1; + prev[1] = -1; + prev[2] = -1; + size_indices = indices ? size_indices : 0; + + for (i = 0; i < count; i += 3) { + int k0, k1, k2; // Current triangle indices + int is_quad = 1; +#if DEBUG_SW_RENDER_GEOMETRY + int is_uniform = 1; + int is_rectangle = 1; +#endif + int A = -1; // Top left vertex + int B = -1; // Bottom right vertex + int C = -1; // Third vertex of current triangle + int C2 = -1; // Last, vertex of previous triangle + + if (size_indices == 4) { + k0 = ((const Uint32 *)indices)[i]; + k1 = ((const Uint32 *)indices)[i + 1]; + k2 = ((const Uint32 *)indices)[i + 2]; + } else if (size_indices == 2) { + k0 = ((const Uint16 *)indices)[i]; + k1 = ((const Uint16 *)indices)[i + 1]; + k2 = ((const Uint16 *)indices)[i + 2]; + } else if (size_indices == 1) { + k0 = ((const Uint8 *)indices)[i]; + k1 = ((const Uint8 *)indices)[i + 1]; + k2 = ((const Uint8 *)indices)[i + 2]; + } else { + /* Vertices were not provided by indices. Maybe some are duplicated. + * We try to indentificate the duplicates by comparing with the previous three vertices */ + k0 = remap_indices(prev, i, texture, xy, xy_stride, color, color_stride, uv, uv_stride); + k1 = remap_indices(prev, i + 1, texture, xy, xy_stride, color, color_stride, uv, uv_stride); + k2 = remap_indices(prev, i + 2, texture, xy, xy_stride, color, color_stride, uv, uv_stride); + } + + if (prev[0] == -1) { + prev[0] = k0; + prev[1] = k1; + prev[2] = k2; + continue; + } + + /* Two triangles forming a quadialateral, + * prev and current triangles must have exactly 2 common vertices */ + { + int cnt = 0, j = 3; + while (j--) { + int p = prev[j]; + if (p == k0 || p == k1 || p == k2) { + cnt++; + } + } + is_quad = (cnt == 2); + } + + // Identify vertices + if (is_quad) { + const float *xy0_, *xy1_, *xy2_; + float x0, x1, x2; + float y0, y1, y2; + xy0_ = (const float *)((const char *)xy + k0 * xy_stride); + xy1_ = (const float *)((const char *)xy + k1 * xy_stride); + xy2_ = (const float *)((const char *)xy + k2 * xy_stride); + x0 = xy0_[0]; + y0 = xy0_[1]; + x1 = xy1_[0]; + y1 = xy1_[1]; + x2 = xy2_[0]; + y2 = xy2_[1]; + + // Find top-left + if (x0 <= x1 && y0 <= y1) { + if (x0 <= x2 && y0 <= y2) { + A = k0; + } else { + A = k2; + } + } else { + if (x1 <= x2 && y1 <= y2) { + A = k1; + } else { + A = k2; + } + } + + // Find bottom-right + if (x0 >= x1 && y0 >= y1) { + if (x0 >= x2 && y0 >= y2) { + B = k0; + } else { + B = k2; + } + } else { + if (x1 >= x2 && y1 >= y2) { + B = k1; + } else { + B = k2; + } + } + + // Find C + if (k0 != A && k0 != B) { + C = k0; + } else if (k1 != A && k1 != B) { + C = k1; + } else { + C = k2; + } + + // Find C2 + if (prev[0] != A && prev[0] != B) { + C2 = prev[0]; + } else if (prev[1] != A && prev[1] != B) { + C2 = prev[1]; + } else { + C2 = prev[2]; + } + + xy0_ = (const float *)((const char *)xy + A * xy_stride); + xy1_ = (const float *)((const char *)xy + B * xy_stride); + xy2_ = (const float *)((const char *)xy + C * xy_stride); + x0 = xy0_[0]; + y0 = xy0_[1]; + x1 = xy1_[0]; + y1 = xy1_[1]; + x2 = xy2_[0]; + y2 = xy2_[1]; + + // Check if triangle A B C is rectangle + if ((x0 == x2 && y1 == y2) || (y0 == y2 && x1 == x2)) { + // ok + } else { + is_quad = 0; +#if DEBUG_SW_RENDER_GEOMETRY + is_rectangle = 0; +#endif + } + + xy2_ = (const float *)((const char *)xy + C2 * xy_stride); + x2 = xy2_[0]; + y2 = xy2_[1]; + + // Check if triangle A B C2 is rectangle + if ((x0 == x2 && y1 == y2) || (y0 == y2 && x1 == x2)) { + // ok + } else { + is_quad = 0; +#if DEBUG_SW_RENDER_GEOMETRY + is_rectangle = 0; +#endif + } + } + + // Check if uniformly colored + if (is_quad) { + const SDL_FColor *col0_ = (const SDL_FColor *)((const char *)color + A * color_stride); + const SDL_FColor *col1_ = (const SDL_FColor *)((const char *)color + B * color_stride); + const SDL_FColor *col2_ = (const SDL_FColor *)((const char *)color + C * color_stride); + const SDL_FColor *col3_ = (const SDL_FColor *)((const char *)color + C2 * color_stride); + if (SDL_memcmp(col0_, col1_, sizeof(*col0_)) == 0 && + SDL_memcmp(col0_, col2_, sizeof(*col0_)) == 0 && + SDL_memcmp(col0_, col3_, sizeof(*col0_)) == 0) { + // ok + } else { + is_quad = 0; +#if DEBUG_SW_RENDER_GEOMETRY + is_uniform = 0; +#endif + } + } + + // Start rendering rect + if (is_quad) { + SDL_FRect s; + SDL_FRect d; + const float *xy0_, *xy1_, *uv0_, *uv1_; + const SDL_FColor *col0_ = (const SDL_FColor *)((const char *)color + k0 * color_stride); + + xy0_ = (const float *)((const char *)xy + A * xy_stride); + xy1_ = (const float *)((const char *)xy + B * xy_stride); + + if (texture) { + uv0_ = (const float *)((const char *)uv + A * uv_stride); + uv1_ = (const float *)((const char *)uv + B * uv_stride); + s.x = uv0_[0] * texw; + s.y = uv0_[1] * texh; + s.w = uv1_[0] * texw - s.x; + s.h = uv1_[1] * texh - s.y; + } else { + s.x = s.y = s.w = s.h = 0; + } + + d.x = xy0_[0]; + d.y = xy0_[1]; + d.w = xy1_[0] - d.x; + d.h = xy1_[1] - d.y; + + // Rect + texture + if (texture && s.w != 0 && s.h != 0) { + SDL_SetTextureAlphaModFloat(texture, col0_->a); + SDL_SetTextureColorModFloat(texture, col0_->r, col0_->g, col0_->b); + if (s.w > 0 && s.h > 0) { + SDL_RenderTexture(renderer, texture, &s, &d); + } else { + int flags = 0; + if (s.w < 0) { + flags |= SDL_FLIP_HORIZONTAL; + s.w *= -1; + s.x -= s.w; + } + if (s.h < 0) { + flags |= SDL_FLIP_VERTICAL; + s.h *= -1; + s.y -= s.h; + } + SDL_RenderTextureRotated(renderer, texture, &s, &d, 0, NULL, (SDL_FlipMode)flags); + } + +#if DEBUG_SW_RENDER_GEOMETRY + SDL_Log("Rect-COPY: RGB %f %f %f - Alpha:%f - texture=%p: src=(%d,%d, %d x %d) dst (%f, %f, %f x %f)", col0_->r, col0_->g, col0_->b, col0_->a, + (void *)texture, s.x, s.y, s.w, s.h, d.x, d.y, d.w, d.h); +#endif + } else if (d.w != 0.0f && d.h != 0.0f) { // Rect, no texture + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColorFloat(renderer, col0_->r, col0_->g, col0_->b, col0_->a); + SDL_RenderFillRect(renderer, &d); +#if DEBUG_SW_RENDER_GEOMETRY + SDL_Log("Rect-FILL: RGB %f %f %f - Alpha:%f - texture=%p: dst (%f, %f, %f x %f)", col0_->r, col0_->g, col0_->b, col0_->a, + (void *)texture, d.x, d.y, d.w, d.h); + } else { + SDL_Log("Rect-DISMISS: RGB %f %f %f - Alpha:%f - texture=%p: src=(%d,%d, %d x %d) dst (%f, %f, %f x %f)", col0_->r, col0_->g, col0_->b, col0_->a, + (void *)texture, s.x, s.y, s.w, s.h, d.x, d.y, d.w, d.h); +#endif + } + + prev[0] = -1; + } else { + // Render triangles + if (prev[0] != -1) { +#if DEBUG_SW_RENDER_GEOMETRY + SDL_Log("Triangle %d %d %d - is_uniform:%d is_rectangle:%d", prev[0], prev[1], prev[2], is_uniform, is_rectangle); +#endif + result = QueueCmdGeometry(renderer, texture, + xy, xy_stride, color, color_stride, uv, uv_stride, + num_vertices, prev, 3, 4, + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + if (!result) { + goto end; + } + } + + prev[0] = k0; + prev[1] = k1; + prev[2] = k2; + } + } // End for (), next triangle + + if (prev[0] != -1) { + // flush the last triangle +#if DEBUG_SW_RENDER_GEOMETRY + SDL_Log("Last triangle %d %d %d", prev[0], prev[1], prev[2]); +#endif + result = QueueCmdGeometry(renderer, texture, + xy, xy_stride, color, color_stride, uv, uv_stride, + num_vertices, prev, 3, 4, + scale_x, scale_y, SDL_TEXTURE_ADDRESS_CLAMP); + if (!result) { + goto end; + } + } + +end: + // Restore + SDL_SetRenderDrawBlendMode(renderer, blendMode); + SDL_SetRenderDrawColorFloat(renderer, r, g, b, a); + + return result; +} +#endif // SDL_VIDEO_RENDER_SW + +bool SDL_RenderGeometryRaw(SDL_Renderer *renderer, + SDL_Texture *texture, + const float *xy, int xy_stride, + const SDL_FColor *color, int color_stride, + const float *uv, int uv_stride, + int num_vertices, + const void *indices, int num_indices, int size_indices) +{ + int i; + int count = indices ? num_indices : num_vertices; + SDL_TextureAddressMode texture_address_mode; + + CHECK_RENDERER_MAGIC(renderer, false); + + if (!renderer->QueueGeometry) { + return SDL_Unsupported(); + } + + if (texture) { + CHECK_TEXTURE_MAGIC(texture, false); + + if (renderer != texture->renderer) { + return SDL_SetError("Texture was not created with this renderer"); + } + } + + if (!xy) { + return SDL_InvalidParamError("xy"); + } + + if (!color) { + return SDL_InvalidParamError("color"); + } + + if (texture && !uv) { + return SDL_InvalidParamError("uv"); + } + + if (count % 3 != 0) { + return SDL_InvalidParamError(indices ? "num_indices" : "num_vertices"); + } + + if (indices) { + if (size_indices != 1 && size_indices != 2 && size_indices != 4) { + return SDL_InvalidParamError("size_indices"); + } + } else { + size_indices = 0; + } + +#if DONT_DRAW_WHILE_HIDDEN + // Don't draw while we're hidden + if (renderer->hidden) { + return true; + } +#endif + + if (num_vertices < 3) { + return true; + } + + if (texture && texture->native) { + texture = texture->native; + } + + texture_address_mode = renderer->texture_address_mode; + if (texture_address_mode == SDL_TEXTURE_ADDRESS_AUTO && texture) { + texture_address_mode = SDL_TEXTURE_ADDRESS_CLAMP; + for (i = 0; i < num_vertices; ++i) { + const float *uv_ = (const float *)((const char *)uv + i * uv_stride); + float u = uv_[0]; + float v = uv_[1]; + if (u < 0.0f || v < 0.0f || u > 1.0f || v > 1.0f) { + texture_address_mode = SDL_TEXTURE_ADDRESS_WRAP; + break; + } + } + } + + if (indices) { + for (i = 0; i < num_indices; ++i) { + int j; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else { + j = ((const Uint8 *)indices)[i]; + } + if (j < 0 || j >= num_vertices) { + return SDL_SetError("Values of 'indices' out of bounds"); + } + } + } + + if (texture) { + texture->last_command_generation = renderer->render_command_generation; + } + + // For the software renderer, try to reinterpret triangles as SDL_Rect +#ifdef SDL_VIDEO_RENDER_SW + if (renderer->software && texture_address_mode == SDL_TEXTURE_ADDRESS_CLAMP) { + return SDL_SW_RenderGeometryRaw(renderer, texture, + xy, xy_stride, color, color_stride, uv, uv_stride, num_vertices, + indices, num_indices, size_indices); + } +#endif + + const SDL_RenderViewState *view = renderer->view; + return QueueCmdGeometry(renderer, texture, + xy, xy_stride, color, color_stride, uv, uv_stride, + num_vertices, indices, num_indices, size_indices, + view->current_scale.x, view->current_scale.y, + texture_address_mode); +} + +SDL_Surface *SDL_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (!renderer->RenderReadPixels) { + SDL_Unsupported(); + return NULL; + } + + FlushRenderCommands(renderer); // we need to render before we read the results. + + SDL_Rect real_rect = renderer->view->pixel_viewport; + + if (rect) { + if (!SDL_GetRectIntersection(rect, &real_rect, &real_rect)) { + SDL_SetError("Can't read outside the current viewport"); + return NULL; + } + } + + SDL_Surface *surface = renderer->RenderReadPixels(renderer, &real_rect); + if (surface) { + SDL_PropertiesID props = SDL_GetSurfaceProperties(surface); + + if (renderer->target) { + SDL_Texture *target = renderer->target; + SDL_Texture *parent = SDL_GetPointerProperty(SDL_GetTextureProperties(target), SDL_PROP_TEXTURE_PARENT_POINTER, NULL); + SDL_PixelFormat expected_format = (parent ? parent->format : target->format); + + SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, target->SDR_white_point); + SDL_SetFloatProperty(props, SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT, target->HDR_headroom); + + // Set the expected surface format + if ((surface->format == SDL_PIXELFORMAT_ARGB8888 && expected_format == SDL_PIXELFORMAT_XRGB8888) || + (surface->format == SDL_PIXELFORMAT_RGBA8888 && expected_format == SDL_PIXELFORMAT_RGBX8888) || + (surface->format == SDL_PIXELFORMAT_ABGR8888 && expected_format == SDL_PIXELFORMAT_XBGR8888) || + (surface->format == SDL_PIXELFORMAT_BGRA8888 && expected_format == SDL_PIXELFORMAT_BGRX8888)) { + surface->format = expected_format; + surface->fmt = SDL_GetPixelFormatDetails(expected_format); + } + } else { + SDL_SetFloatProperty(props, SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, renderer->SDR_white_point); + SDL_SetFloatProperty(props, SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT, renderer->HDR_headroom); + } + } + return surface; +} + +static void SDL_RenderApplyWindowShape(SDL_Renderer *renderer) +{ + SDL_Surface *shape = (SDL_Surface *)SDL_GetPointerProperty(SDL_GetWindowProperties(renderer->window), SDL_PROP_WINDOW_SHAPE_POINTER, NULL); + if (shape != renderer->shape_surface) { + if (renderer->shape_texture) { + SDL_DestroyTexture(renderer->shape_texture); + renderer->shape_texture = NULL; + } + + if (shape) { + // There's nothing we can do if this fails, so just keep on going + renderer->shape_texture = SDL_CreateTextureFromSurface(renderer, shape); + + SDL_SetTextureBlendMode(renderer->shape_texture, + SDL_ComposeCustomBlendMode( + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD, + SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD)); + } + renderer->shape_surface = shape; + } + + if (renderer->shape_texture) { + SDL_RenderTexture(renderer, renderer->shape_texture, NULL, NULL); + } +} + +static void SDL_SimulateRenderVSync(SDL_Renderer *renderer) +{ + Uint64 now, elapsed; + const Uint64 interval = renderer->simulate_vsync_interval_ns; + + if (!interval) { + // We can't do sub-ns delay, so just return here + return; + } + + now = SDL_GetTicksNS(); + elapsed = (now - renderer->last_present); + if (elapsed < interval) { + Uint64 duration = (interval - elapsed); + SDL_DelayPrecise(duration); + now = SDL_GetTicksNS(); + } + + elapsed = (now - renderer->last_present); + if (!renderer->last_present || elapsed > SDL_MS_TO_NS(1000)) { + // It's been too long, reset the presentation timeline + renderer->last_present = now; + } else { + renderer->last_present += (elapsed / interval) * interval; + } +} + +bool SDL_RenderPresent(SDL_Renderer *renderer) +{ + bool presented = true; + + CHECK_RENDERER_MAGIC(renderer, false); + + SDL_Texture *target = renderer->target; + if (target) { + SDL_SetRenderTarget(renderer, NULL); + } + + SDL_RenderLogicalPresentation(renderer); + + if (renderer->transparent_window) { + SDL_RenderApplyWindowShape(renderer); + } + + FlushRenderCommands(renderer); // time to send everything to the GPU! + +#if DONT_DRAW_WHILE_HIDDEN + // Don't present while we're hidden + if (renderer->hidden) { + presented = false; + } else +#endif + if (!renderer->RenderPresent(renderer)) { + presented = false; + } + + if (target) { + SDL_SetRenderTarget(renderer, target); + } + + if (renderer->simulate_vsync || + (!presented && renderer->wanted_vsync)) { + SDL_SimulateRenderVSync(renderer); + } + return true; +} + +static void SDL_DestroyTextureInternal(SDL_Texture *texture, bool is_destroying) +{ + SDL_Renderer *renderer; + + SDL_DestroyProperties(texture->props); + + renderer = texture->renderer; + if (is_destroying) { + // Renderer get destroyed, avoid to queue more commands + } else { + if (texture == renderer->target) { + SDL_SetRenderTarget(renderer, NULL); // implies command queue flush + } else { + FlushRenderCommandsIfTextureNeeded(texture); + } + } + + SDL_SetObjectValid(texture, SDL_OBJECT_TYPE_TEXTURE, false); + + if (texture->next) { + texture->next->prev = texture->prev; + } + if (texture->prev) { + texture->prev->next = texture->next; + } else { + renderer->textures = texture->next; + } + + if (texture->native) { + SDL_DestroyTextureInternal(texture->native, is_destroying); + } +#ifdef SDL_HAVE_YUV + if (texture->yuv) { + SDL_SW_DestroyYUVTexture(texture->yuv); + } +#endif + SDL_free(texture->pixels); + + renderer->DestroyTexture(renderer, texture); + + SDL_DestroySurface(texture->locked_surface); + texture->locked_surface = NULL; + + SDL_free(texture); +} + +void SDL_DestroyTexture(SDL_Texture *texture) +{ + CHECK_TEXTURE_MAGIC(texture, ); + + if (--texture->refcount > 0) { + return; + } + + SDL_DestroyTextureInternal(texture, false /* is_destroying */); +} + +static void SDL_DiscardAllCommands(SDL_Renderer *renderer) +{ + SDL_RenderCommand *cmd; + + if (renderer->render_commands_tail) { + renderer->render_commands_tail->next = renderer->render_commands_pool; + cmd = renderer->render_commands; + } else { + cmd = renderer->render_commands_pool; + } + + renderer->render_commands_pool = NULL; + renderer->render_commands_tail = NULL; + renderer->render_commands = NULL; + renderer->vertex_data_used = 0; + + while (cmd) { + SDL_RenderCommand *next = cmd->next; + SDL_free(cmd); + cmd = next; + } +} + +void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) +{ + SDL_assert(renderer != NULL); + SDL_assert(!renderer->destroyed); + + renderer->destroyed = true; + + SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, SDL_RendererEventWatch, renderer); + + if (renderer->window) { + SDL_PropertiesID props = SDL_GetWindowProperties(renderer->window); + if (SDL_GetPointerProperty(props, SDL_PROP_WINDOW_RENDERER_POINTER, NULL) == renderer) { + SDL_ClearProperty(props, SDL_PROP_WINDOW_RENDERER_POINTER); + } + SDL_RemoveWindowRenderer(renderer->window, renderer); + } + + if (renderer->software) { + // Make sure all drawing to a surface is complete + FlushRenderCommands(renderer); + } + SDL_DiscardAllCommands(renderer); + + if (renderer->debug_char_texture_atlas) { + SDL_DestroyTexture(renderer->debug_char_texture_atlas); + renderer->debug_char_texture_atlas = NULL; + } + + // Free existing textures for this renderer + while (renderer->textures) { + SDL_Texture *tex = renderer->textures; + SDL_DestroyTextureInternal(renderer->textures, true /* is_destroying */); + SDL_assert(tex != renderer->textures); // satisfy static analysis. + } + + // Clean up renderer-specific resources + if (renderer->DestroyRenderer) { + renderer->DestroyRenderer(renderer); + } + + if (renderer->target_mutex) { + SDL_DestroyMutex(renderer->target_mutex); + renderer->target_mutex = NULL; + } + if (renderer->vertex_data) { + SDL_free(renderer->vertex_data); + renderer->vertex_data = NULL; + } + if (renderer->texture_formats) { + SDL_free(renderer->texture_formats); + renderer->texture_formats = NULL; + } + if (renderer->props) { + SDL_DestroyProperties(renderer->props); + renderer->props = 0; + } +} + +void SDL_DestroyRenderer(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC_BUT_NOT_DESTROYED_FLAG(renderer,); + + // if we've already destroyed the renderer through SDL_DestroyWindow, we just need + // to free the renderer pointer. This lets apps destroy the window and renderer + // in either order. + if (!renderer->destroyed) { + SDL_DestroyRendererWithoutFreeing(renderer); + } + + SDL_Renderer *curr = SDL_renderers; + SDL_Renderer *prev = NULL; + while (curr) { + if (curr == renderer) { + if (prev) { + prev->next = renderer->next; + } else { + SDL_renderers = renderer->next; + } + break; + } + prev = curr; + curr = curr->next; + } + + SDL_SetObjectValid(renderer, SDL_OBJECT_TYPE_RENDERER, false); // It's no longer magical... + + SDL_free(renderer); +} + +void *SDL_GetRenderMetalLayer(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (renderer->GetMetalLayer) { + FlushRenderCommands(renderer); // in case the app is going to mess with it. + return renderer->GetMetalLayer(renderer); + } + return NULL; +} + +void *SDL_GetRenderMetalCommandEncoder(SDL_Renderer *renderer) +{ + CHECK_RENDERER_MAGIC(renderer, NULL); + + if (renderer->GetMetalCommandEncoder) { + FlushRenderCommands(renderer); // in case the app is going to mess with it. + return renderer->GetMetalCommandEncoder(renderer); + } + return NULL; +} + +bool SDL_AddVulkanRenderSemaphores(SDL_Renderer *renderer, Uint32 wait_stage_mask, Sint64 wait_semaphore, Sint64 signal_semaphore) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + if (!renderer->AddVulkanRenderSemaphores) { + return SDL_Unsupported(); + } + return renderer->AddVulkanRenderSemaphores(renderer, wait_stage_mask, wait_semaphore, signal_semaphore); +} + +static SDL_BlendMode SDL_GetShortBlendMode(SDL_BlendMode blendMode) +{ + if (blendMode == SDL_BLENDMODE_NONE_FULL) { + return SDL_BLENDMODE_NONE; + } + if (blendMode == SDL_BLENDMODE_BLEND_FULL) { + return SDL_BLENDMODE_BLEND; + } + if (blendMode == SDL_BLENDMODE_BLEND_PREMULTIPLIED_FULL) { + return SDL_BLENDMODE_BLEND_PREMULTIPLIED; + } + if (blendMode == SDL_BLENDMODE_ADD_FULL) { + return SDL_BLENDMODE_ADD; + } + if (blendMode == SDL_BLENDMODE_ADD_PREMULTIPLIED_FULL) { + return SDL_BLENDMODE_ADD_PREMULTIPLIED; + } + if (blendMode == SDL_BLENDMODE_MOD_FULL) { + return SDL_BLENDMODE_MOD; + } + if (blendMode == SDL_BLENDMODE_MUL_FULL) { + return SDL_BLENDMODE_MUL; + } + return blendMode; +} + +static SDL_BlendMode SDL_GetLongBlendMode(SDL_BlendMode blendMode) +{ + if (blendMode == SDL_BLENDMODE_NONE) { + return SDL_BLENDMODE_NONE_FULL; + } + if (blendMode == SDL_BLENDMODE_BLEND) { + return SDL_BLENDMODE_BLEND_FULL; + } + if (blendMode == SDL_BLENDMODE_BLEND_PREMULTIPLIED) { + return SDL_BLENDMODE_BLEND_PREMULTIPLIED_FULL; + } + if (blendMode == SDL_BLENDMODE_ADD) { + return SDL_BLENDMODE_ADD_FULL; + } + if (blendMode == SDL_BLENDMODE_ADD_PREMULTIPLIED) { + return SDL_BLENDMODE_ADD_PREMULTIPLIED_FULL; + } + if (blendMode == SDL_BLENDMODE_MOD) { + return SDL_BLENDMODE_MOD_FULL; + } + if (blendMode == SDL_BLENDMODE_MUL) { + return SDL_BLENDMODE_MUL_FULL; + } + return blendMode; +} + +SDL_BlendMode SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor, SDL_BlendFactor dstColorFactor, + SDL_BlendOperation colorOperation, + SDL_BlendFactor srcAlphaFactor, SDL_BlendFactor dstAlphaFactor, + SDL_BlendOperation alphaOperation) +{ + SDL_BlendMode blendMode = SDL_COMPOSE_BLENDMODE(srcColorFactor, dstColorFactor, colorOperation, + srcAlphaFactor, dstAlphaFactor, alphaOperation); + return SDL_GetShortBlendMode(blendMode); +} + +SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendFactor)(((Uint32)blendMode >> 4) & 0xF); +} + +SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendFactor)(((Uint32)blendMode >> 8) & 0xF); +} + +SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendOperation)(((Uint32)blendMode >> 0) & 0xF); +} + +SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendFactor)(((Uint32)blendMode >> 20) & 0xF); +} + +SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendFactor)(((Uint32)blendMode >> 24) & 0xF); +} + +SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode) +{ + blendMode = SDL_GetLongBlendMode(blendMode); + return (SDL_BlendOperation)(((Uint32)blendMode >> 16) & 0xF); +} + +bool SDL_SetRenderVSync(SDL_Renderer *renderer, int vsync) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + renderer->wanted_vsync = vsync ? true : false; + + // for the software renderer, forward the call to the WindowTexture renderer +#ifdef SDL_VIDEO_RENDER_SW + if (renderer->software) { + if (!renderer->window) { + if (!vsync) { + return true; + } else { + return SDL_Unsupported(); + } + } + if (SDL_SetWindowTextureVSync(NULL, renderer->window, vsync)) { + renderer->simulate_vsync = false; + return true; + } + } +#endif + + if (!renderer->SetVSync) { + switch (vsync) { + case 0: + renderer->simulate_vsync = false; + break; + case 1: + renderer->simulate_vsync = true; + break; + default: + return SDL_Unsupported(); + } + } else if (!renderer->SetVSync(renderer, vsync)) { + if (vsync == 1) { + renderer->simulate_vsync = true; + } else { + return false; + } + } + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VSYNC_NUMBER, vsync); + return true; +} + +bool SDL_GetRenderVSync(SDL_Renderer *renderer, int *vsync) +{ + if (vsync) { + *vsync = 0; + } + + CHECK_RENDERER_MAGIC(renderer, false); + + if (vsync) { + *vsync = (int)SDL_GetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_VSYNC_NUMBER, 0); + } + return true; +} + + +#define SDL_DEBUG_FONT_GLYPHS_PER_ROW 14 + +static bool CreateDebugTextAtlas(SDL_Renderer *renderer) +{ + SDL_assert(renderer->debug_char_texture_atlas == NULL); // don't double-create it! + + const int charWidth = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + const int charHeight = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + + // actually make each glyph two pixels taller/wider, to prevent scaling artifacts. + const int rows = (SDL_DEBUG_FONT_NUM_GLYPHS / SDL_DEBUG_FONT_GLYPHS_PER_ROW) + 1; + SDL_Surface *atlas = SDL_CreateSurface((charWidth + 2) * SDL_DEBUG_FONT_GLYPHS_PER_ROW, rows * (charHeight + 2), SDL_PIXELFORMAT_RGBA8888); + if (!atlas) { + return false; + } + + const int pitch = atlas->pitch; + SDL_memset(atlas->pixels, '\0', atlas->h * atlas->pitch); + + int column = 0; + int row = 0; + for (int glyph = 0; glyph < SDL_DEBUG_FONT_NUM_GLYPHS; glyph++) { + // find top-left of this glyph in destination surface. The +2's account for glyph padding. + Uint8 *linepos = (((Uint8 *)atlas->pixels) + ((row * (charHeight + 2) + 1) * pitch)) + ((column * (charWidth + 2) + 1) * sizeof (Uint32)); + const Uint8 *charpos = SDL_RenderDebugTextFontData + (glyph * 8); + + // Draw the glyph to the surface... + for (int iy = 0; iy < charHeight; iy++) { + Uint32 *curpos = (Uint32 *)linepos; + for (int ix = 0; ix < charWidth; ix++) { + if ((*charpos) & (1 << ix)) { + *curpos = 0xffffffff; + } else { + *curpos = 0; + } + ++curpos; + } + linepos += pitch; + ++charpos; + } + + // move to next position (and if too far, start the next row). + column++; + if (column >= SDL_DEBUG_FONT_GLYPHS_PER_ROW) { + row++; + column = 0; + } + } + + SDL_assert((row < rows) || ((row == rows) && (column == 0))); // make sure we didn't overflow the surface. + + // Convert temp surface into texture + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, atlas); + if (texture) { + SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); + renderer->debug_char_texture_atlas = texture; + } + SDL_DestroySurface(atlas); + + return texture != NULL; +} + +static bool DrawDebugCharacter(SDL_Renderer *renderer, float x, float y, Uint32 c) +{ + SDL_assert(renderer->debug_char_texture_atlas != NULL); // should have been created by now! + + const int charWidth = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + const int charHeight = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + + // Character index in cache + Uint32 ci = c; + if ((ci <= 32) || ((ci >= 127) && (ci <= 160))) { + return true; // these are just completely blank chars, don't bother doing anything. + } else if (ci >= SDL_DEBUG_FONT_NUM_GLYPHS) { + ci = SDL_DEBUG_FONT_NUM_GLYPHS - 1; // use our "not a valid/supported character" glyph. + } else if (ci < 127) { + ci -= 33; // adjust for the 33 blank glyphs at the start + } else { + ci -= 67; // adjust for the 33 blank glyphs at the start AND the 34 gap in the middle. + } + + const float src_x = (float) (((ci % SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charWidth + 2)) + 1); + const float src_y = (float) (((ci / SDL_DEBUG_FONT_GLYPHS_PER_ROW) * (charHeight + 2)) + 1); + + // Draw texture onto destination + const SDL_FRect srect = { src_x, src_y, (float) charWidth, (float) charHeight }; + const SDL_FRect drect = { x, y, (float) charWidth, (float) charHeight }; + return SDL_RenderTexture(renderer, renderer->debug_char_texture_atlas, &srect, &drect); +} + +bool SDL_RenderDebugText(SDL_Renderer *renderer, float x, float y, const char *s) +{ + CHECK_RENDERER_MAGIC(renderer, false); + + // Allocate a texture atlas for this renderer if needed. + if (!renderer->debug_char_texture_atlas) { + if (!CreateDebugTextAtlas(renderer)) { + return false; + } + } + + bool result = true; + + Uint8 r, g, b, a; + result &= SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a); + result &= SDL_SetTextureColorMod(renderer->debug_char_texture_atlas, r, g, b); + result &= SDL_SetTextureAlphaMod(renderer->debug_char_texture_atlas, a); + + float curx = x; + Uint32 ch; + + while (result && ((ch = SDL_StepUTF8(&s, NULL)) != 0)) { + result &= DrawDebugCharacter(renderer, curx, y, ch); + curx += SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE; + } + + return result; +} + +bool SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + // fast path to avoid unnecessary allocation and copy. If you're going through the dynapi, there's a good chance + // you _always_ hit this path, since it probably had to process varargs before calling into the jumptable. + if (SDL_strcmp(fmt, "%s") == 0) { + const char *str = va_arg(ap, const char *); + va_end(ap); + return SDL_RenderDebugText(renderer, x, y, str); + } + + char *str = NULL; + const int rc = SDL_vasprintf(&str, fmt, ap); + va_end(ap); + + if (rc == -1) { + return false; + } + + const bool retval = SDL_RenderDebugText(renderer, x, y, str); + SDL_free(str); + return retval; +} diff --git a/contrib/SDL-3.2.8/src/render/SDL_render_debug_font.h b/contrib/SDL-3.2.8/src/render/SDL_render_debug_font.h new file mode 100644 index 0000000..ca296e8 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_render_debug_font.h @@ -0,0 +1,2331 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_render_debug_font_h_ +#define SDL_render_debug_font_h_ + +/* ---- 8x8 font definition ---- */ + +/* +; Summary: font8_8.asm +; 8x8 monochrome bitmap fonts for rendering +; +; Author: +; Marcel Sondaar +; International Business Machines (public domain VGA fonts) +; +; License: +; Public Domain +; +*/ + +#define SDL_DEBUG_FONT_NUM_GLYPHS 190 + +static const Uint8 SDL_RenderDebugTextFontData[] = { + // there's a gap at the start. + + /* + * 33 0x21 '!' + */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 34 0x22 '"' + */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 35 0x23 '#' + */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x7f, /* 11111110 */ + 0x36, /* 01101100 */ + 0x7f, /* 11111110 */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + + /* + * 36 0x24 '$' + */ + 0x0c, /* 00110000 */ + 0x3e, /* 01111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 37 0x25 '%' + */ + 0x00, /* 00000000 */ + 0x63, /* 11000110 */ + 0x33, /* 11001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x66, /* 01100110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 38 0x26 '&' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x33, /* 11001100 */ + 0x6e, /* 01110110 */ + 0x00, /* 00000000 */ + + /* + * 39 0x27 ''' + */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 40 0x28 '(' + */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 41 0x29 ')' + */ + 0x06, /* 01100000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x00, /* 00000000 */ + + /* + * 42 0x2a '*' + */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0xff, /* 11111111 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 43 0x2b '+' + */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x3f, /* 11111100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 44 0x2c ',' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + + /* + * 45 0x2d '-' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 46 0x2e '.' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 47 0x2f '/' + */ + 0x60, /* 00000110 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + 0x01, /* 10000000 */ + 0x00, /* 00000000 */ + + /* + * 48 0x30 '0' + */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x73, /* 11001110 */ + 0x7b, /* 11011110 */ + 0x6f, /* 11110110 */ + 0x67, /* 11100110 */ + 0x3e, /* 01111100 */ + 0x00, /* 00000000 */ + + /* + * 49 0x31 '1' + */ + 0x0c, /* 00110000 */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 50 0x32 '2' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x30, /* 00001100 */ + 0x1c, /* 00111000 */ + 0x06, /* 01100000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 51 0x33 '3' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x30, /* 00001100 */ + 0x1c, /* 00111000 */ + 0x30, /* 00001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 52 0x34 '4' + */ + 0x38, /* 00011100 */ + 0x3c, /* 00111100 */ + 0x36, /* 01101100 */ + 0x33, /* 11001100 */ + 0x7f, /* 11111110 */ + 0x30, /* 00001100 */ + 0x78, /* 00011110 */ + 0x00, /* 00000000 */ + + /* + * 53 0x35 '5' + */ + 0x3f, /* 11111100 */ + 0x03, /* 11000000 */ + 0x1f, /* 11111000 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 54 0x36 '6' + */ + 0x1c, /* 00111000 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + 0x1f, /* 11111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 55 0x37 '7' + */ + 0x3f, /* 11111100 */ + 0x33, /* 11001100 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 56 0x38 '8' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 57 0x39 '9' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0e, /* 01110000 */ + 0x00, /* 00000000 */ + + /* + * 58 0x3a ':' + */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 59 0x3b ';' + */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + + /* + * 60 0x3c '<' + */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + 0x06, /* 01100000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 61 0x3d '=' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 62 0x3e '>' + */ + 0x06, /* 01100000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x00, /* 00000000 */ + + /* + * 63 0x3f '?' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 64 0x40 '@' + */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x7b, /* 11011110 */ + 0x7b, /* 11011110 */ + 0x7b, /* 11011110 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 65 0x41 'A' + */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 66 0x42 'B' + */ + 0x3f, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 67 0x43 'C' + */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 68 0x44 'D' + */ + 0x1f, /* 11111000 */ + 0x36, /* 01101100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x36, /* 01101100 */ + 0x1f, /* 11111000 */ + 0x00, /* 00000000 */ + + /* + * 69 0x45 'E' + */ + 0x7f, /* 11111110 */ + 0x46, /* 01100010 */ + 0x16, /* 01101000 */ + 0x1e, /* 01111000 */ + 0x16, /* 01101000 */ + 0x46, /* 01100010 */ + 0x7f, /* 11111110 */ + 0x00, /* 00000000 */ + + /* + * 70 0x46 'F' + */ + 0x7f, /* 11111110 */ + 0x46, /* 01100010 */ + 0x16, /* 01101000 */ + 0x1e, /* 01111000 */ + 0x16, /* 01101000 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + 0x00, /* 00000000 */ + + /* + * 71 0x47 'G' + */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + 0x73, /* 11001110 */ + 0x66, /* 01100110 */ + 0x7c, /* 00111110 */ + 0x00, /* 00000000 */ + + /* + * 72 0x48 'H' + */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 73 0x49 'I' + */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 74 0x4a 'J' + */ + 0x78, /* 00011110 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 75 0x4b 'K' + */ + 0x67, /* 11100110 */ + 0x66, /* 01100110 */ + 0x36, /* 01101100 */ + 0x1e, /* 01111000 */ + 0x36, /* 01101100 */ + 0x66, /* 01100110 */ + 0x67, /* 11100110 */ + 0x00, /* 00000000 */ + + /* + * 76 0x4c 'L' + */ + 0x0f, /* 11110000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x46, /* 01100010 */ + 0x66, /* 01100110 */ + 0x7f, /* 11111110 */ + 0x00, /* 00000000 */ + + /* + * 77 0x4d 'M' + */ + 0x63, /* 11000110 */ + 0x77, /* 11101110 */ + 0x7f, /* 11111110 */ + 0x7f, /* 11111110 */ + 0x6b, /* 11010110 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 78 0x4e 'N' + */ + 0x63, /* 11000110 */ + 0x67, /* 11100110 */ + 0x6f, /* 11110110 */ + 0x7b, /* 11011110 */ + 0x73, /* 11001110 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 79 0x4f 'O' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + + /* + * 80 0x50 'P' + */ + 0x3f, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + 0x00, /* 00000000 */ + + /* + * 81 0x51 'Q' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3b, /* 11011100 */ + 0x1e, /* 01111000 */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + + /* + * 82 0x52 'R' + */ + 0x3f, /* 11111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x36, /* 01101100 */ + 0x66, /* 01100110 */ + 0x67, /* 11100110 */ + 0x00, /* 00000000 */ + + /* + * 83 0x53 'S' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x07, /* 11100000 */ + 0x0e, /* 01110000 */ + 0x38, /* 00011100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 84 0x54 'T' + */ + 0x3f, /* 11111100 */ + 0x2d, /* 10110100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 85 0x55 'U' + */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 86 0x56 'V' + */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 87 0x57 'W' + */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x6b, /* 11010110 */ + 0x7f, /* 11111110 */ + 0x77, /* 11101110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 88 0x58 'X' + */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 89 0x59 'Y' + */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 90 0x5a 'Z' + */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x31, /* 10001100 */ + 0x18, /* 00011000 */ + 0x4c, /* 00110010 */ + 0x66, /* 01100110 */ + 0x7f, /* 11111110 */ + 0x00, /* 00000000 */ + + /* + * 91 0x5b '[' + */ + 0x1e, /* 01111000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 92 0x5c '\' + */ + 0x03, /* 11000000 */ + 0x06, /* 01100000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x30, /* 00001100 */ + 0x60, /* 00000110 */ + 0x40, /* 00000010 */ + 0x00, /* 00000000 */ + + /* + * 93 0x5d ']' + */ + 0x1e, /* 01111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 94 0x5e '^' + */ + 0x08, /* 00010000 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 95 0x5f '_' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xff, /* 11111111 */ + + /* + * 96 0x60 '`' + */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 97 0x61 'a' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x6e, /* 01110110 */ + 0x00, /* 00000000 */ + + /* + * 98 0x62 'b' + */ + 0x07, /* 11100000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x3e, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3b, /* 11011100 */ + 0x00, /* 00000000 */ + + /* + * 99 0x63 'c' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x03, /* 11000000 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 100 0x64 'd' + */ + 0x38, /* 00011100 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x6e, /* 01110110 */ + 0x00, /* 00000000 */ + + /* + * 101 0x65 'e' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 102 0x66 'f' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + 0x06, /* 01100000 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + 0x00, /* 00000000 */ + + /* + * 103 0x67 'g' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6e, /* 01110110 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + + /* + * 104 0x68 'h' + */ + 0x07, /* 11100000 */ + 0x06, /* 01100000 */ + 0x36, /* 01101100 */ + 0x6e, /* 01110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x67, /* 11100110 */ + 0x00, /* 00000000 */ + + /* + * 105 0x69 'i' + */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 106 0x6a 'j' + */ + 0x30, /* 00001100 */ + 0x00, /* 00000000 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + + /* + * 107 0x6b 'k' + */ + 0x07, /* 11100000 */ + 0x06, /* 01100000 */ + 0x66, /* 01100110 */ + 0x36, /* 01101100 */ + 0x1e, /* 01111000 */ + 0x36, /* 01101100 */ + 0x67, /* 11100110 */ + 0x00, /* 00000000 */ + + /* + * 108 0x6c 'l' + */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 109 0x6d 'm' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x7f, /* 11111110 */ + 0x7f, /* 11111110 */ + 0x6b, /* 11010110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 110 0x6e 'n' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1f, /* 11111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 111 0x6f 'o' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 112 0x70 'p' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3b, /* 11011100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + + /* + * 113 0x71 'q' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x6e, /* 01110110 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x78, /* 00011110 */ + + /* + * 114 0x72 'r' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3b, /* 11011100 */ + 0x6e, /* 01110110 */ + 0x66, /* 01100110 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + 0x00, /* 00000000 */ + + /* + * 115 0x73 's' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3e, /* 01111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + 0x00, /* 00000000 */ + + /* + * 116 0x74 't' + */ + 0x08, /* 00010000 */ + 0x0c, /* 00110000 */ + 0x3e, /* 01111100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x2c, /* 00110100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 117 0x75 'u' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x6e, /* 01110110 */ + 0x00, /* 00000000 */ + + /* + * 118 0x76 'v' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + + /* + * 119 0x77 'w' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x63, /* 11000110 */ + 0x6b, /* 11010110 */ + 0x7f, /* 11111110 */ + 0x7f, /* 11111110 */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + + /* + * 120 0x78 'x' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x63, /* 11000110 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 121 0x79 'y' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + + /* + * 122 0x7a 'z' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x19, /* 10011000 */ + 0x0c, /* 00110000 */ + 0x26, /* 01100100 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 123 0x7b '{' + */ + 0x38, /* 00011100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x07, /* 11100000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + + /* + * 124 0x7c '|' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 125 0x7d '}' + */ + 0x07, /* 11100000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x38, /* 00011100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + + /* + * 126 0x7e '~' + */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + // there's a gap here. + + /* + * 161 0xa1 '¡' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 162 0xa2 '¢' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + + /* + * 163 0xa3 '£' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x26, /* 01100100 */ + 0x0f, /* 11110000 */ + 0x06, /* 01100000 */ + 0x67, /* 11100110 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 164 0xa4 '¤' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x63, /* 11000110 */ + 0x3e, /* 01111100 */ + 0x36, /* 01101100 */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 165 0xa5 'Â¥' + */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x3f, /* 11111100 */ + 0x0c, /* 00110000 */ + 0x3f, /* 11111100 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + + /* + * 166 0xa6 '¦' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 167 0xa7 '§' + */ + 0x7c, /* 00111110 */ + 0xc6, /* 01100011 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + + /* + * 168 0xa8 '¨' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 169 0xa9 '©' + */ + 0x3c, /* 00111100 */ + 0x42, /* 01000010 */ + 0x99, /* 10011001 */ + 0x85, /* 10100001 */ + 0x85, /* 10100001 */ + 0x99, /* 10011001 */ + 0x42, /* 01000010 */ + 0x3c, /* 00111100 */ + + /* + * 170 0xaa 'ª' + */ + 0x3c, /* 00111100 */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x7c, /* 00111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 171 0xab '«' + */ + 0x00, /* 00000000 */ + 0xcc, /* 00110011 */ + 0x66, /* 01100110 */ + 0x33, /* 11001100 */ + 0x66, /* 01100110 */ + 0xcc, /* 00110011 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 172 0xac '¬' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x30, /* 00001100 */ + 0x30, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 173 0xad '­' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 174 0xae '®' + */ + 0x3c, /* 00111100 */ + 0x42, /* 01000010 */ + 0x9d, /* 10111001 */ + 0xa5, /* 10100101 */ + 0x9d, /* 10111001 */ + 0xa5, /* 10100101 */ + 0x42, /* 01000010 */ + 0x3c, /* 00111100 */ + + /* + * 175 0xaf '¯' + */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 176 0xb0 '°' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 177 0xb1 '±' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x7e, /* 01111110 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 178 0xb2 '²' + */ + 0x1c, /* 00111000 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 179 0xb3 '³' + */ + 0x1c, /* 00111000 */ + 0x30, /* 00001100 */ + 0x18, /* 00011000 */ + 0x30, /* 00001100 */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 180 0xb4 '´' + */ + 0x18, /* 00011000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 181 0xb5 'µ' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + + /* + * 182 0xb6 '¶' + */ + 0xfe, /* 01111111 */ + 0xdb, /* 11011011 */ + 0xdb, /* 11011011 */ + 0xde, /* 01111011 */ + 0xd8, /* 00011011 */ + 0xd8, /* 00011011 */ + 0xd8, /* 00011011 */ + 0x00, /* 00000000 */ + + /* + * 183 0xb7 '·' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 184 0xb8 '¸' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x30, /* 00001100 */ + 0x1e, /* 01111000 */ + + /* + * 185 0xb9 '¹' + */ + 0x08, /* 00010000 */ + 0x0c, /* 00110000 */ + 0x08, /* 00010000 */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 186 0xba 'º' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 187 0xbb '»' + */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x66, /* 01100110 */ + 0xcc, /* 00110011 */ + 0x66, /* 01100110 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 188 0xbc '¼' + */ + 0xc3, /* 11000011 */ + 0x63, /* 11000110 */ + 0x33, /* 11001100 */ + 0xbd, /* 10111101 */ + 0xec, /* 00110111 */ + 0xf6, /* 01101111 */ + 0xf3, /* 11001111 */ + 0x03, /* 11000000 */ + + /* + * 189 0xbd '½' + */ + 0xc3, /* 11000011 */ + 0x63, /* 11000110 */ + 0x33, /* 11001100 */ + 0x7b, /* 11011110 */ + 0xcc, /* 00110011 */ + 0x66, /* 01100110 */ + 0x33, /* 11001100 */ + 0xf0, /* 00001111 */ + + /* + * 190 0xbe '¾' + */ + 0x03, /* 11000000 */ + 0xc4, /* 00100011 */ + 0x63, /* 11000110 */ + 0xb4, /* 00101101 */ + 0xdb, /* 11011011 */ + 0xac, /* 00110101 */ + 0xe6, /* 01100111 */ + 0x80, /* 00000001 */ + + /* + * 191 0xbf '¿' + */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x0c, /* 00110000 */ + 0x06, /* 01100000 */ + 0x03, /* 11000000 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 192 0xc0 'À' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 193 0xc1 'Á' + */ + 0x70, /* 00001110 */ + 0x00, /* 00000000 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 194 0xc2 'Â' + */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 195 0xc3 'Ã' + */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x00, /* 00000000 */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 196 0xc4 'Ä' + */ + 0x63, /* 11000110 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x63, /* 11000110 */ + 0x7f, /* 11111110 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x00, /* 00000000 */ + + /* + * 197 0xc5 'Å' + */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 198 0xc6 'Æ' + */ + 0x7c, /* 00111110 */ + 0x36, /* 01101100 */ + 0x33, /* 11001100 */ + 0x7f, /* 11111110 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x73, /* 11001110 */ + 0x00, /* 00000000 */ + + /* + * 199 0xc7 'Ç' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x03, /* 11000000 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x18, /* 00011000 */ + 0x30, /* 00001100 */ + 0x1e, /* 01111000 */ + + /* + * 200 0xc8 'È' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x06, /* 01100000 */ + 0x1e, /* 01111000 */ + 0x06, /* 01100000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 201 0xc9 'É' + */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x06, /* 01100000 */ + 0x1e, /* 01111000 */ + 0x06, /* 01100000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 202 0xca 'Ê' + */ + 0x0c, /* 00110000 */ + 0x12, /* 01001000 */ + 0x3f, /* 11111100 */ + 0x06, /* 01100000 */ + 0x1e, /* 01111000 */ + 0x06, /* 01100000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 203 0xcb 'Ë' + */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + 0x3f, /* 11111100 */ + 0x06, /* 01100000 */ + 0x1e, /* 01111000 */ + 0x06, /* 01100000 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 204 0xcc 'Ì' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 205 0xcd 'Í' + */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 206 0xce 'Î' + */ + 0x0c, /* 00110000 */ + 0x12, /* 01001000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 207 0xcf 'Ï' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 208 0xd0 'Ð' + */ + 0x3f, /* 11111100 */ + 0x66, /* 01100110 */ + 0x6f, /* 11110110 */ + 0x6f, /* 11110110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + + /* + * 209 0xd1 'Ñ' + */ + 0x3f, /* 11111100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x37, /* 11101100 */ + 0x3f, /* 11111100 */ + 0x3b, /* 11011100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 210 0xd2 'Ò' + */ + 0x0e, /* 01110000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 211 0xd3 'Ó' + */ + 0x70, /* 00001110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 212 0xd4 'Ô' + */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 213 0xd5 'Õ' + */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x00, /* 00000000 */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x63, /* 11000110 */ + 0x3e, /* 01111100 */ + 0x00, /* 00000000 */ + + /* + * 214 0xd6 'Ö' + */ + 0xc3, /* 11000011 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 215 0xd7 '×' + */ + 0x00, /* 00000000 */ + 0x36, /* 01101100 */ + 0x1c, /* 00111000 */ + 0x08, /* 00010000 */ + 0x1c, /* 00111000 */ + 0x36, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* + * 216 0xd8 'Ø' + */ + 0x5c, /* 00111010 */ + 0x36, /* 01101100 */ + 0x73, /* 11001110 */ + 0x7b, /* 11011110 */ + 0x6f, /* 11110110 */ + 0x36, /* 01101100 */ + 0x1d, /* 10111000 */ + 0x00, /* 00000000 */ + + /* + * 217 0xd9 'Ù' + */ + 0x0e, /* 01110000 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 218 0xda 'Ú' + */ + 0x70, /* 00001110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 219 0xdb 'Û' + */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 220 0xdc 'Ü' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 221 0xdd 'Ý' + */ + 0x70, /* 00001110 */ + 0x00, /* 00000000 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3c, /* 00111100 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 222 0xde 'Þ' + */ + 0x0f, /* 11110000 */ + 0x06, /* 01100000 */ + 0x3e, /* 01111100 */ + 0x66, /* 01100110 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x06, /* 01100000 */ + 0x0f, /* 11110000 */ + + /* + * 223 0xdf 'ß' + */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x1f, /* 11111000 */ + 0x33, /* 11001100 */ + 0x1f, /* 11111000 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + + /* + * 224 0xe0 'à' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 225 0xe1 'á' + */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 226 0xe2 'â' + */ + 0x7e, /* 01111110 */ + 0xc3, /* 11000011 */ + 0x3c, /* 00111100 */ + 0x60, /* 00000110 */ + 0x7c, /* 00111110 */ + 0x66, /* 01100110 */ + 0xfc, /* 00111111 */ + 0x00, /* 00000000 */ + + /* + * 227 0xe3 'ã' + */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 228 0xe4 'ä' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 229 0xe5 'Ã¥' + */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 230 0xe6 'æ' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xfe, /* 01111111 */ + 0x30, /* 00001100 */ + 0xfe, /* 01111111 */ + 0x33, /* 11001100 */ + 0xfe, /* 01111111 */ + 0x00, /* 00000000 */ + + /* + * 231 0xe7 'ç' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x03, /* 11000000 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x30, /* 00001100 */ + 0x1c, /* 00111000 */ + + /* + * 232 0xe8 'è' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 233 0xe9 'é' + */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 234 0xea 'ê' + */ + 0x7e, /* 01111110 */ + 0xc3, /* 11000011 */ + 0x3c, /* 00111100 */ + 0x66, /* 01100110 */ + 0x7e, /* 01111110 */ + 0x06, /* 01100000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 235 0xeb 'ë' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x3f, /* 11111100 */ + 0x03, /* 11000000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 236 0xec 'ì' + */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 237 0xed 'í' + */ + 0x1c, /* 00111000 */ + 0x00, /* 00000000 */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 238 0xee 'î' + */ + 0x3e, /* 01111100 */ + 0x63, /* 11000110 */ + 0x1c, /* 00111000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x3c, /* 00111100 */ + 0x00, /* 00000000 */ + + /* + * 239 0xef 'ï' + */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x0e, /* 01110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x0c, /* 00110000 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 240 0xf0 'ð' + */ + 0x1b, /* 11011000 */ + 0x0e, /* 01110000 */ + 0x1b, /* 11011000 */ + 0x30, /* 00001100 */ + 0x3e, /* 01111100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 241 0xf1 'ñ' + */ + 0x00, /* 00000000 */ + 0x1f, /* 11111000 */ + 0x00, /* 00000000 */ + 0x1f, /* 11111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + + /* + * 242 0xf2 'ò' + */ + 0x00, /* 00000000 */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 243 0xf3 'ó' + */ + 0x00, /* 00000000 */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 244 0xf4 'ô' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 245 0xf5 'õ' + */ + 0x6e, /* 01110110 */ + 0x3b, /* 11011100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 246 0xf6 'ö' + */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x1e, /* 01111000 */ + 0x00, /* 00000000 */ + + /* + * 247 0xf7 '÷' + */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* + * 248 0xf8 'ø' + */ + 0x00, /* 00000000 */ + 0x60, /* 00000110 */ + 0x3c, /* 00111100 */ + 0x76, /* 01101110 */ + 0x7e, /* 01111110 */ + 0x6e, /* 01110110 */ + 0x3c, /* 00111100 */ + 0x06, /* 01100000 */ + + /* + * 249 0xf9 'ù' + */ + 0x00, /* 00000000 */ + 0x07, /* 11100000 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 250 0xfa 'ú' + */ + 0x00, /* 00000000 */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 251 0xfb 'û' + */ + 0x1e, /* 01111000 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 252 0xfc 'ü' + */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x7e, /* 01111110 */ + 0x00, /* 00000000 */ + + /* + * 253 0xfd 'ý' + */ + 0x00, /* 00000000 */ + 0x38, /* 00011100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + + /* + * 254 0xfe 'þ' + */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x06, /* 01100000 */ + 0x3e, /* 01111100 */ + 0x66, /* 01100110 */ + 0x3e, /* 01111100 */ + 0x06, /* 01100000 */ + 0x00, /* 00000000 */ + + /* + * 255 0xff 'ÿ' + */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x00, /* 00000000 */ + 0x33, /* 11001100 */ + 0x33, /* 11001100 */ + 0x3e, /* 01111100 */ + 0x30, /* 00001100 */ + 0x1f, /* 11111000 */ + + /* + * 256 0x100 - missing character + */ + 0x55, /* 01010101 */ + 0xAA, /* 10101010 */ + 0x55, /* 01010101 */ + 0xAA, /* 10101010 */ + 0x55, /* 01010101 */ + 0xAA, /* 10101010 */ + 0x55, /* 01010101 */ + 0xAA, /* 10101010 */ +}; + +SDL_COMPILE_TIME_ASSERT(SDL_RenderDebugTextFontDataSize, SDL_arraysize(SDL_RenderDebugTextFontData) == SDL_DEBUG_FONT_NUM_GLYPHS * 8); + +#endif + diff --git a/contrib/SDL-3.2.8/src/render/SDL_render_unsupported.c b/contrib/SDL-3.2.8/src/render/SDL_render_unsupported.c new file mode 100644 index 0000000..5369fb4 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_render_unsupported.c @@ -0,0 +1,22 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + diff --git a/contrib/SDL-3.2.8/src/render/SDL_sysrender.h b/contrib/SDL-3.2.8/src/render/SDL_sysrender.h new file mode 100644 index 0000000..9d39dfd --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_sysrender.h @@ -0,0 +1,372 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_sysrender_h_ +#define SDL_sysrender_h_ + +#include "../video/SDL_surface_c.h" + +#include "SDL_yuv_sw_c.h" + +// Set up for C function definitions, even when using C++ +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum SDL_TextureAddressMode +{ + SDL_TEXTURE_ADDRESS_AUTO, + SDL_TEXTURE_ADDRESS_CLAMP, + SDL_TEXTURE_ADDRESS_WRAP, +} SDL_TextureAddressMode; + +/** + * A rectangle, with the origin at the upper left (double precision). + */ +typedef struct SDL_DRect +{ + double x; + double y; + double w; + double h; +} SDL_DRect; + +// The SDL 2D rendering system + +typedef struct SDL_RenderDriver SDL_RenderDriver; + +// Rendering view state +typedef struct SDL_RenderViewState +{ + int pixel_w; + int pixel_h; + SDL_Rect viewport; + SDL_Rect pixel_viewport; + SDL_Rect clip_rect; + SDL_Rect pixel_clip_rect; + bool clipping_enabled; + SDL_FPoint scale; + + // Support for logical output coordinates + SDL_RendererLogicalPresentation logical_presentation_mode; + int logical_w, logical_h; + SDL_FRect logical_src_rect; + SDL_FRect logical_dst_rect; + SDL_FPoint logical_scale; + SDL_FPoint logical_offset; + + SDL_FPoint current_scale; // this is just `scale * logical_scale`, precalculated, since we use it a lot. +} SDL_RenderViewState; + +// Define the SDL texture structure +struct SDL_Texture +{ + // Public API definition + SDL_PixelFormat format; /**< The format of the texture, read-only */ + int w; /**< The width of the texture, read-only. */ + int h; /**< The height of the texture, read-only. */ + + int refcount; /**< Application reference count, used when freeing texture */ + + // Private API definition + SDL_Colorspace colorspace; // The colorspace of the texture + float SDR_white_point; // The SDR white point for this content + float HDR_headroom; // The HDR headroom needed by this content + SDL_TextureAccess access; // The texture access mode + SDL_BlendMode blendMode; // The texture blend mode + SDL_ScaleMode scaleMode; // The texture scale mode + SDL_FColor color; // Texture modulation values + SDL_RenderViewState view; // Target texture view state + + SDL_Renderer *renderer; + + // Support for formats not supported directly by the renderer + SDL_Texture *native; + SDL_SW_YUVTexture *yuv; + void *pixels; + int pitch; + SDL_Rect locked_rect; + SDL_Surface *locked_surface; // Locked region exposed as a SDL surface + + Uint32 last_command_generation; // last command queue generation this texture was in. + + SDL_PropertiesID props; + + void *internal; // Driver specific texture representation + + SDL_Texture *prev; + SDL_Texture *next; +}; + +typedef enum +{ + SDL_RENDERCMD_NO_OP, + SDL_RENDERCMD_SETVIEWPORT, + SDL_RENDERCMD_SETCLIPRECT, + SDL_RENDERCMD_SETDRAWCOLOR, + SDL_RENDERCMD_CLEAR, + SDL_RENDERCMD_DRAW_POINTS, + SDL_RENDERCMD_DRAW_LINES, + SDL_RENDERCMD_FILL_RECTS, + SDL_RENDERCMD_COPY, + SDL_RENDERCMD_COPY_EX, + SDL_RENDERCMD_GEOMETRY +} SDL_RenderCommandType; + +typedef struct SDL_RenderCommand +{ + SDL_RenderCommandType command; + union + { + struct + { + size_t first; + SDL_Rect rect; + } viewport; + struct + { + bool enabled; + SDL_Rect rect; + } cliprect; + struct + { + size_t first; + size_t count; + float color_scale; + SDL_FColor color; + SDL_BlendMode blend; + SDL_Texture *texture; + SDL_TextureAddressMode texture_address_mode; + } draw; + struct + { + size_t first; + float color_scale; + SDL_FColor color; + } color; + } data; + struct SDL_RenderCommand *next; +} SDL_RenderCommand; + +typedef struct SDL_VertexSolid +{ + SDL_FPoint position; + SDL_FColor color; +} SDL_VertexSolid; + +typedef enum +{ + SDL_RENDERLINEMETHOD_POINTS, + SDL_RENDERLINEMETHOD_LINES, + SDL_RENDERLINEMETHOD_GEOMETRY, +} SDL_RenderLineMethod; + +// Define the SDL renderer structure +struct SDL_Renderer +{ + void (*WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event); + bool (*GetOutputSize)(SDL_Renderer *renderer, int *w, int *h); + bool (*SupportsBlendMode)(SDL_Renderer *renderer, SDL_BlendMode blendMode); + bool (*CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props); + bool (*QueueSetViewport)(SDL_Renderer *renderer, SDL_RenderCommand *cmd); + bool (*QueueSetDrawColor)(SDL_Renderer *renderer, SDL_RenderCommand *cmd); + bool (*QueueDrawPoints)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, + int count); + bool (*QueueDrawLines)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, + int count); + bool (*QueueFillRects)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, + int count); + bool (*QueueCopy)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const SDL_FRect *srcrect, const SDL_FRect *dstrect); + bool (*QueueCopyEx)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const SDL_FRect *srcquad, const SDL_FRect *dstrect, + const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y); + bool (*QueueGeometry)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y); + + void (*InvalidateCachedState)(SDL_Renderer *renderer); + bool (*RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize); + bool (*UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, const void *pixels, + int pitch); +#ifdef SDL_HAVE_YUV + bool (*UpdateTextureYUV)(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch); + bool (*UpdateTextureNV)(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); +#endif + bool (*LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, void **pixels, int *pitch); + void (*UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture); + void (*SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode); + bool (*SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture); + SDL_Surface *(*RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect); + bool (*RenderPresent)(SDL_Renderer *renderer); + void (*DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture); + + void (*DestroyRenderer)(SDL_Renderer *renderer); + + bool (*SetVSync)(SDL_Renderer *renderer, int vsync); + + void *(*GetMetalLayer)(SDL_Renderer *renderer); + void *(*GetMetalCommandEncoder)(SDL_Renderer *renderer); + + bool (*AddVulkanRenderSemaphores)(SDL_Renderer *renderer, Uint32 wait_stage_mask, Sint64 wait_semaphore, Sint64 signal_semaphore); + + // The current renderer info + const char *name; + SDL_PixelFormat *texture_formats; + int num_texture_formats; + bool software; + + // The window associated with the renderer + SDL_Window *window; + bool hidden; + + // Whether we should simulate vsync + bool wanted_vsync; + bool simulate_vsync; + Uint64 simulate_vsync_interval_ns; + Uint64 last_present; + + SDL_RenderViewState *view; + SDL_RenderViewState main_view; + + // The window pixel to point coordinate scale + SDL_FPoint dpi_scale; + + // The method of drawing lines + SDL_RenderLineMethod line_method; + + // The list of textures + SDL_Texture *textures; + SDL_Texture *target; + SDL_Mutex *target_mutex; + + SDL_Colorspace output_colorspace; + float SDR_white_point; + float HDR_headroom; + + float desired_color_scale; + float color_scale; + SDL_FColor color; /**< Color for drawing operations values */ + SDL_BlendMode blendMode; /**< The drawing blend mode */ + SDL_TextureAddressMode texture_address_mode; + + SDL_RenderCommand *render_commands; + SDL_RenderCommand *render_commands_tail; + SDL_RenderCommand *render_commands_pool; + Uint32 render_command_generation; + SDL_FColor last_queued_color; + float last_queued_color_scale; + SDL_Rect last_queued_viewport; + SDL_Rect last_queued_cliprect; + bool last_queued_cliprect_enabled; + bool color_queued; + bool viewport_queued; + bool cliprect_queued; + + void *vertex_data; + size_t vertex_data_used; + size_t vertex_data_allocation; + + // Shaped window support + bool transparent_window; + SDL_Surface *shape_surface; + SDL_Texture *shape_texture; + + SDL_PropertiesID props; + + SDL_Texture *debug_char_texture_atlas; + + bool destroyed; // already destroyed by SDL_DestroyWindow; just free this struct in SDL_DestroyRenderer. + + void *internal; + + SDL_Renderer *next; +}; + +// Define the SDL render driver structure +struct SDL_RenderDriver +{ + bool (*CreateRenderer)(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID props); + + const char *name; +}; + +// Not all of these are available in a given build. Use #ifdefs, etc. +extern SDL_RenderDriver D3D_RenderDriver; +extern SDL_RenderDriver D3D11_RenderDriver; +extern SDL_RenderDriver D3D12_RenderDriver; +extern SDL_RenderDriver GL_RenderDriver; +extern SDL_RenderDriver GLES2_RenderDriver; +extern SDL_RenderDriver METAL_RenderDriver; +extern SDL_RenderDriver VULKAN_RenderDriver; +extern SDL_RenderDriver PS2_RenderDriver; +extern SDL_RenderDriver PSP_RenderDriver; +extern SDL_RenderDriver SW_RenderDriver; +extern SDL_RenderDriver VITA_GXM_RenderDriver; +extern SDL_RenderDriver GPU_RenderDriver; + +// Clean up any renderers at shutdown +extern void SDL_QuitRender(void); + +// Add a supported texture format to a renderer +extern bool SDL_AddSupportedTextureFormat(SDL_Renderer *renderer, SDL_PixelFormat format); + +// Setup colorspace conversion +extern void SDL_SetupRendererColorspace(SDL_Renderer *renderer, SDL_PropertiesID props); + +// Colorspace conversion functions +extern bool SDL_RenderingLinearSpace(SDL_Renderer *renderer); +extern void SDL_ConvertToLinear(SDL_FColor *color); +extern void SDL_ConvertFromLinear(SDL_FColor *color); + +// Blend mode functions +extern SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode); +extern SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode); +extern SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode); +extern SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode); +extern SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode); +extern SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode); + +/* drivers call this during their Queue*() methods to make space in a array that are used + for a vertex buffer during RunCommandQueue(). Pointers returned here are only valid until + the next call, because it might be in an array that gets realloc()'d. */ +extern void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, size_t numbytes, size_t alignment, size_t *offset); + +// Let the video subsystem destroy a renderer without making its pointer invalid. +extern void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer); + +// Ends C function definitions when using C++ +#ifdef __cplusplus +} +#endif + +#endif // SDL_sysrender_h_ diff --git a/contrib/SDL-3.2.8/src/render/SDL_yuv_sw.c b/contrib/SDL-3.2.8/src/render/SDL_yuv_sw.c new file mode 100644 index 0000000..abe9e16 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_yuv_sw.c @@ -0,0 +1,404 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// This is the software implementation of the YUV texture support + +#ifdef SDL_HAVE_YUV + +#include "SDL_yuv_sw_c.h" +#include "../video/SDL_surface_c.h" +#include "../video/SDL_yuv_c.h" + +SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspace colorspace, int w, int h) +{ + SDL_SW_YUVTexture *swdata; + + switch (format) { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_YUY2: + case SDL_PIXELFORMAT_UYVY: + case SDL_PIXELFORMAT_YVYU: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + break; + default: + SDL_SetError("Unsupported YUV format"); + return NULL; + } + + swdata = (SDL_SW_YUVTexture *)SDL_calloc(1, sizeof(*swdata)); + if (!swdata) { + return NULL; + } + + swdata->format = format; + swdata->colorspace = colorspace; + swdata->target_format = SDL_PIXELFORMAT_UNKNOWN; + swdata->w = w; + swdata->h = h; + { + size_t dst_size; + if (!SDL_CalculateYUVSize(format, w, h, &dst_size, NULL)) { + SDL_SW_DestroyYUVTexture(swdata); + return NULL; + } + swdata->pixels = (Uint8 *)SDL_aligned_alloc(SDL_GetSIMDAlignment(), dst_size); + if (!swdata->pixels) { + SDL_SW_DestroyYUVTexture(swdata); + return NULL; + } + } + + // Find the pitch and offset values for the texture + switch (format) { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + swdata->pitches[0] = w; + swdata->pitches[1] = (swdata->pitches[0] + 1) / 2; + swdata->pitches[2] = (swdata->pitches[0] + 1) / 2; + swdata->planes[0] = swdata->pixels; + swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h; + swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2); + break; + case SDL_PIXELFORMAT_YUY2: + case SDL_PIXELFORMAT_UYVY: + case SDL_PIXELFORMAT_YVYU: + swdata->pitches[0] = ((w + 1) / 2) * 4; + swdata->planes[0] = swdata->pixels; + break; + + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + swdata->pitches[0] = w; + swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2); + swdata->planes[0] = swdata->pixels; + swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h; + break; + + default: + SDL_assert(!"We should never get here (caught above)"); + break; + } + + // We're all done.. + return swdata; +} + +bool SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture *swdata, void **pixels, + int *pitch) +{ + *pixels = swdata->planes[0]; + *pitch = swdata->pitches[0]; + return true; +} + +bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + const void *pixels, int pitch) +{ + switch (swdata->format) { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + if (rect->x == 0 && rect->y == 0 && + rect->w == swdata->w && rect->h == swdata->h) { + SDL_memcpy(swdata->pixels, pixels, + (size_t)(swdata->h * swdata->w) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2)); + } else { + Uint8 *src, *dst; + int row; + size_t length; + + // Copy the Y plane + src = (Uint8 *)pixels; + dst = swdata->pixels + rect->y * swdata->w + rect->x; + length = rect->w; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->w; + } + + // Copy the next plane + src = (Uint8 *)pixels + rect->h * pitch; + dst = swdata->pixels + swdata->h * swdata->w; + dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += (pitch + 1) / 2; + dst += (swdata->w + 1) / 2; + } + + // Copy the next plane + src = (Uint8 *)pixels + rect->h * pitch + ((rect->h + 1) / 2) * ((pitch + 1) / 2); + dst = swdata->pixels + swdata->h * swdata->w + + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); + dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += (pitch + 1) / 2; + dst += (swdata->w + 1) / 2; + } + } + break; + case SDL_PIXELFORMAT_YUY2: + case SDL_PIXELFORMAT_UYVY: + case SDL_PIXELFORMAT_YVYU: + { + Uint8 *src, *dst; + int row; + size_t length; + + src = (Uint8 *)pixels; + dst = + swdata->planes[0] + rect->y * swdata->pitches[0] + + rect->x * 2; + length = 4 * (((size_t)rect->w + 1) / 2); + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->pitches[0]; + } + } break; + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + { + if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) { + SDL_memcpy(swdata->pixels, pixels, + (size_t)(swdata->h * swdata->w) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2)); + } else { + + Uint8 *src, *dst; + int row; + size_t length; + + // Copy the Y plane + src = (Uint8 *)pixels; + dst = swdata->pixels + rect->y * swdata->w + rect->x; + length = rect->w; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += swdata->w; + } + + // Copy the next plane + src = (Uint8 *)pixels + rect->h * pitch; + dst = swdata->pixels + swdata->h * swdata->w; + dst += 2 * ((rect->y + 1) / 2) * ((swdata->w + 1) / 2) + 2 * (rect->x / 2); + length = 2 * (((size_t)rect->w + 1) / 2); + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += 2 * ((pitch + 1) / 2); + dst += 2 * ((swdata->w + 1) / 2); + } + } + } break; + default: + return SDL_SetError("Unsupported YUV format"); + } + return true; +} + +bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) +{ + const Uint8 *src; + Uint8 *dst; + int row; + size_t length; + + // Copy the Y plane + src = Yplane; + dst = swdata->pixels + rect->y * swdata->w + rect->x; + length = rect->w; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += Ypitch; + dst += swdata->w; + } + + // Copy the U plane + src = Uplane; + if (swdata->format == SDL_PIXELFORMAT_IYUV) { + dst = swdata->pixels + swdata->h * swdata->w; + } else { + dst = swdata->pixels + swdata->h * swdata->w + + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); + } + dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += Upitch; + dst += (swdata->w + 1) / 2; + } + + // Copy the V plane + src = Vplane; + if (swdata->format == SDL_PIXELFORMAT_YV12) { + dst = swdata->pixels + swdata->h * swdata->w; + } else { + dst = swdata->pixels + swdata->h * swdata->w + + ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2); + } + dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2; + length = (rect->w + 1) / 2; + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += Vpitch; + dst += (swdata->w + 1) / 2; + } + return true; +} + +bool SDL_SW_UpdateNVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ + const Uint8 *src; + Uint8 *dst; + int row; + size_t length; + + // Copy the Y plane + src = Yplane; + dst = swdata->pixels + rect->y * swdata->w + rect->x; + length = rect->w; + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += Ypitch; + dst += swdata->w; + } + + // Copy the UV or VU plane + src = UVplane; + dst = swdata->pixels + swdata->h * swdata->w; + dst += rect->y * ((swdata->w + 1) / 2) + rect->x; + length = (rect->w + 1) / 2; + length *= 2; + for (row = 0; row < (rect->h + 1) / 2; ++row) { + SDL_memcpy(dst, src, length); + src += UVpitch; + dst += 2 * ((swdata->w + 1) / 2); + } + + return true; +} + +bool SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + void **pixels, int *pitch) +{ + switch (swdata->format) { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + if (rect && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w || rect->h != swdata->h)) { + return SDL_SetError("YV12, IYUV, NV12, NV21 textures only support full surface locks"); + } + break; + default: + return SDL_SetError("Unsupported YUV format"); + } + + if (rect) { + *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2; + } else { + *pixels = swdata->planes[0]; + } + *pitch = swdata->pitches[0]; + return true; +} + +void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture *swdata) +{ +} + +bool SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture *swdata, const SDL_Rect *srcrect, SDL_PixelFormat target_format, int w, int h, void *pixels, int pitch) +{ + int stretch; + + // Make sure we're set up to display in the desired format + if (target_format != swdata->target_format && swdata->display) { + SDL_DestroySurface(swdata->display); + swdata->display = NULL; + } + + stretch = 0; + if (srcrect->x || srcrect->y || srcrect->w < swdata->w || srcrect->h < swdata->h) { + /* The source rectangle has been clipped. + Using a scratch surface is easier than adding clipped + source support to all the blitters, plus that would + slow them down in the general unclipped case. + */ + stretch = 1; + } else if ((srcrect->w != w) || (srcrect->h != h)) { + stretch = 1; + } + if (stretch) { + if (swdata->display) { + swdata->display->w = w; + swdata->display->h = h; + swdata->display->pixels = pixels; + swdata->display->pitch = pitch; + } else { + swdata->display = SDL_CreateSurfaceFrom(w, h, target_format, pixels, pitch); + if (!swdata->display) { + return false; + } + swdata->target_format = target_format; + } + if (!swdata->stretch) { + swdata->stretch = SDL_CreateSurface(swdata->w, swdata->h, target_format); + if (!swdata->stretch) { + return false; + } + } + pixels = swdata->stretch->pixels; + pitch = swdata->stretch->pitch; + } + if (!SDL_ConvertPixelsAndColorspace(swdata->w, swdata->h, swdata->format, swdata->colorspace, 0, swdata->planes[0], swdata->pitches[0], target_format, SDL_COLORSPACE_SRGB, 0, pixels, pitch)) { + return false; + } + if (stretch) { + SDL_Rect rect = *srcrect; + return SDL_StretchSurface(swdata->stretch, &rect, swdata->display, NULL, SDL_SCALEMODE_NEAREST); + } else { + return true; + } +} + +void SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture *swdata) +{ + if (swdata) { + SDL_aligned_free(swdata->pixels); + SDL_DestroySurface(swdata->stretch); + SDL_DestroySurface(swdata->display); + SDL_free(swdata); + } +} + +#endif // SDL_HAVE_YUV diff --git a/contrib/SDL-3.2.8/src/render/SDL_yuv_sw_c.h b/contrib/SDL-3.2.8/src/render/SDL_yuv_sw_c.h new file mode 100644 index 0000000..807c44c --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/SDL_yuv_sw_c.h @@ -0,0 +1,63 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_yuv_sw_c_h_ +#define SDL_yuv_sw_c_h_ + +#include "SDL_internal.h" + +// This is the software implementation of the YUV texture support + +struct SDL_SW_YUVTexture +{ + SDL_PixelFormat format; + SDL_Colorspace colorspace; + SDL_PixelFormat target_format; + int w, h; + Uint8 *pixels; + + // These are just so we don't have to allocate them separately + int pitches[3]; + Uint8 *planes[3]; + + // This is a temporary surface in case we have to stretch copy + SDL_Surface *stretch; + SDL_Surface *display; +}; + +typedef struct SDL_SW_YUVTexture SDL_SW_YUVTexture; + +extern SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspace colorspace, int w, int h); +extern bool SDL_SW_QueryYUVTexturePixels(SDL_SW_YUVTexture *swdata, void **pixels, int *pitch); +extern bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, const void *pixels, int pitch); +extern bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch); +extern bool SDL_SW_UpdateNVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); +extern bool SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect, void **pixels, int *pitch); +extern void SDL_SW_UnlockYUVTexture(SDL_SW_YUVTexture *swdata); +extern bool SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture *swdata, const SDL_Rect *srcrect, SDL_PixelFormat target_format, int w, int h, void *pixels, int pitch); +extern void SDL_SW_DestroyYUVTexture(SDL_SW_YUVTexture *swdata); + +#endif // SDL_yuv_sw_c_h_ diff --git a/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.h b/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.h new file mode 100644 index 0000000..e6d9130 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.h @@ -0,0 +1,164 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// Parameters: +// +// float4 Bcoeff; +// float4 Gcoeff; +// float4 Rcoeff; +// float4 Yoffset; +// Texture2D theSampler+theTextureU; +// Texture2D theSampler+theTextureV; +// Texture2D theSampler+theTextureY; +// +// +// Registers: +// +// Name Reg Size +// ---------------------- ----- ---- +// Yoffset c0 1 +// Rcoeff c1 1 +// Gcoeff c2 1 +// Bcoeff c3 1 +// theSampler+theTextureY s0 1 +// theSampler+theTextureU s1 1 +// theSampler+theTextureV s2 1 +// + + ps_2_0 + def c4, 1, 0, 0, 0 + dcl t0.xy + dcl v0 + dcl_2d s0 + dcl_2d s1 + dcl_2d s2 + texld r0, t0, s0 + texld r1, t0, s1 + texld r2, t0, s2 + mov r0.y, r1.x + mov r0.z, r2.x + add r0.xyz, r0, c0 + dp3 r1.x, r0, c1 + dp3 r1.y, r0, c2 + dp3 r1.z, r0, c3 + mov r1.w, c4.x + mul r0, r1, v0 + mov oC0, r0 + +// approximately 12 instruction slots used (3 texture, 9 arithmetic) +#endif + +const BYTE g_ps20_main[] = +{ + 0, 2, 255, 255, 254, 255, + 97, 0, 67, 84, 65, 66, + 28, 0, 0, 0, 87, 1, + 0, 0, 0, 2, 255, 255, + 7, 0, 0, 0, 28, 0, + 0, 0, 0, 1, 0, 0, + 80, 1, 0, 0, 168, 0, + 0, 0, 2, 0, 3, 0, + 1, 0, 0, 0, 176, 0, + 0, 0, 0, 0, 0, 0, + 192, 0, 0, 0, 2, 0, + 2, 0, 1, 0, 0, 0, + 176, 0, 0, 0, 0, 0, + 0, 0, 199, 0, 0, 0, + 2, 0, 1, 0, 1, 0, + 0, 0, 176, 0, 0, 0, + 0, 0, 0, 0, 206, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 176, 0, + 0, 0, 0, 0, 0, 0, + 214, 0, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 240, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, + 3, 0, 2, 0, 1, 0, + 0, 0, 24, 1, 0, 0, + 0, 0, 0, 0, 40, 1, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 64, 1, + 0, 0, 0, 0, 0, 0, + 66, 99, 111, 101, 102, 102, + 0, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 71, 99, 111, 101, 102, 102, + 0, 82, 99, 111, 101, 102, + 102, 0, 89, 111, 102, 102, + 115, 101, 116, 0, 116, 104, + 101, 83, 97, 109, 112, 108, + 101, 114, 43, 116, 104, 101, + 84, 101, 120, 116, 117, 114, + 101, 85, 0, 171, 171, 171, + 4, 0, 7, 0, 1, 0, + 4, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 116, 104, + 101, 83, 97, 109, 112, 108, + 101, 114, 43, 116, 104, 101, + 84, 101, 120, 116, 117, 114, + 101, 86, 0, 171, 4, 0, + 7, 0, 1, 0, 4, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 116, 104, 101, 83, + 97, 109, 112, 108, 101, 114, + 43, 116, 104, 101, 84, 101, + 120, 116, 117, 114, 101, 89, + 0, 171, 4, 0, 7, 0, + 1, 0, 4, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 112, 115, 95, 50, 95, 48, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 49, 48, 46, 49, 0, 171, + 81, 0, 0, 5, 4, 0, + 15, 160, 0, 0, 128, 63, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 3, 176, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 15, 144, + 31, 0, 0, 2, 0, 0, + 0, 144, 0, 8, 15, 160, + 31, 0, 0, 2, 0, 0, + 0, 144, 1, 8, 15, 160, + 31, 0, 0, 2, 0, 0, + 0, 144, 2, 8, 15, 160, + 66, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 176, + 0, 8, 228, 160, 66, 0, + 0, 3, 1, 0, 15, 128, + 0, 0, 228, 176, 1, 8, + 228, 160, 66, 0, 0, 3, + 2, 0, 15, 128, 0, 0, + 228, 176, 2, 8, 228, 160, + 1, 0, 0, 2, 0, 0, + 2, 128, 1, 0, 0, 128, + 1, 0, 0, 2, 0, 0, + 4, 128, 2, 0, 0, 128, + 2, 0, 0, 3, 0, 0, + 7, 128, 0, 0, 228, 128, + 0, 0, 228, 160, 8, 0, + 0, 3, 1, 0, 1, 128, + 0, 0, 228, 128, 1, 0, + 228, 160, 8, 0, 0, 3, + 1, 0, 2, 128, 0, 0, + 228, 128, 2, 0, 228, 160, + 8, 0, 0, 3, 1, 0, + 4, 128, 0, 0, 228, 128, + 3, 0, 228, 160, 1, 0, + 0, 2, 1, 0, 8, 128, + 4, 0, 0, 160, 5, 0, + 0, 3, 0, 0, 15, 128, + 1, 0, 228, 128, 0, 0, + 228, 144, 1, 0, 0, 2, + 0, 8, 15, 128, 0, 0, + 228, 128, 255, 255, 0, 0 +}; diff --git a/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.hlsl b/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.hlsl new file mode 100644 index 0000000..8804848 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/D3D9_PixelShader_YUV.hlsl @@ -0,0 +1,47 @@ + +Texture2D theTextureY : register(t0); +Texture2D theTextureU : register(t1); +Texture2D theTextureV : register(t2); + +SamplerState theSampler = sampler_state +{ + addressU = Clamp; + addressV = Clamp; + mipfilter = NONE; + minfilter = LINEAR; + magfilter = LINEAR; +}; + +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; +}; + +cbuffer Constants : register(b0) +{ + float4 Yoffset; + float4 Rcoeff; + float4 Gcoeff; + float4 Bcoeff; +}; + + +float4 main(PixelShaderInput input) : SV_TARGET +{ + float4 Output; + + float3 yuv; + yuv.x = theTextureY.Sample(theSampler, input.tex).r; + yuv.y = theTextureU.Sample(theSampler, input.tex).r; + yuv.z = theTextureV.Sample(theSampler, input.tex).r; + + yuv += Yoffset.xyz; + Output.r = dot(yuv, Rcoeff.xyz); + Output.g = dot(yuv, Gcoeff.xyz); + Output.b = dot(yuv, Bcoeff.xyz); + Output.a = 1.0f; + + return Output * input.color; +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d/SDL_render_d3d.c b/contrib/SDL-3.2.8/src/render/direct3d/SDL_render_d3d.c new file mode 100644 index 0000000..ccb5b3c --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/SDL_render_d3d.c @@ -0,0 +1,1778 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_D3D + +#include "../../core/windows/SDL_windows.h" + +#include "../SDL_sysrender.h" +#include "../SDL_d3dmath.h" +#include "../../video/windows/SDL_windowsvideo.h" +#include "../../video/SDL_pixels_c.h" + +#define D3D_DEBUG_INFO +#include + +#include "SDL_shaders_d3d.h" + +typedef struct +{ + SDL_Rect viewport; + bool viewport_dirty; + SDL_Texture *texture; + SDL_BlendMode blend; + bool cliprect_enabled; + bool cliprect_enabled_dirty; + SDL_Rect cliprect; + bool cliprect_dirty; + D3D9_Shader shader; + const float *shader_params; +} D3D_DrawStateCache; + +// Direct3D renderer implementation + +typedef struct +{ + void *d3dDLL; + IDirect3D9 *d3d; + IDirect3DDevice9 *device; + UINT adapter; + D3DPRESENT_PARAMETERS pparams; + bool updateSize; + bool beginScene; + bool enableSeparateAlphaBlend; + D3DTEXTUREFILTERTYPE scaleMode[3]; + SDL_TextureAddressMode addressMode[3]; + IDirect3DSurface9 *defaultRenderTarget; + IDirect3DSurface9 *currentRenderTarget; + void *d3dxDLL; +#ifdef SDL_HAVE_YUV + LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS]; +#endif + LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8]; + size_t vertexBufferSize[8]; + int currentVertexBuffer; + bool reportedVboProblem; + D3D_DrawStateCache drawstate; +} D3D_RenderData; + +typedef struct +{ + bool dirty; + int w, h; + DWORD usage; + Uint32 format; + D3DFORMAT d3dfmt; + IDirect3DTexture9 *texture; + IDirect3DTexture9 *staging; +} D3D_TextureRep; + +typedef struct +{ + D3D_TextureRep texture; + D3DTEXTUREFILTERTYPE scaleMode; + D3D9_Shader shader; + const float *shader_params; + +#ifdef SDL_HAVE_YUV + // YV12 texture support + bool yuv; + D3D_TextureRep utexture; + D3D_TextureRep vtexture; + Uint8 *pixels; + int pitch; + SDL_Rect locked_rect; +#endif +} D3D_TextureData; + +typedef struct +{ + float x, y, z; + DWORD color; + float u, v; +} Vertex; + +static bool 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; + } + return SDL_SetError("%s: %s", prefix, error); +} + +static D3DFORMAT PixelFormatToD3DFMT(Uint32 format) +{ + switch (format) { + case SDL_PIXELFORMAT_RGB565: + return D3DFMT_R5G6B5; + case SDL_PIXELFORMAT_XRGB8888: + return D3DFMT_X8R8G8B8; + case SDL_PIXELFORMAT_ARGB8888: + 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; + } +} + +static SDL_PixelFormat D3DFMTToPixelFormat(D3DFORMAT format) +{ + switch (format) { + case D3DFMT_R5G6B5: + return SDL_PIXELFORMAT_RGB565; + case D3DFMT_X8R8G8B8: + return SDL_PIXELFORMAT_XRGB8888; + case D3DFMT_A8R8G8B8: + return SDL_PIXELFORMAT_ARGB8888; + default: + return SDL_PIXELFORMAT_UNKNOWN; + } +} + +static void D3D_InitRenderState(D3D_RenderData *data) +{ + D3DMATRIX matrix; + + IDirect3DDevice9 *device = data->device; + IDirect3DDevice9_SetPixelShader(device, NULL); + IDirect3DDevice9_SetTexture(device, 0, NULL); + IDirect3DDevice9_SetTexture(device, 1, NULL); + IDirect3DDevice9_SetTexture(device, 2, NULL); + IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1); + IDirect3DDevice9_SetVertexShader(device, NULL); + IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE); + IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE); + IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE); + + // Enable color modulation by diffuse color + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP, + D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1, + D3DTA_TEXTURE); + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2, + D3DTA_DIFFUSE); + + // Enable alpha modulation by diffuse alpha + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP, + D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1, + D3DTA_TEXTURE); + IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2, + D3DTA_DIFFUSE); + + // Enable separate alpha blend function, if possible + if (data->enableSeparateAlphaBlend) { + IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + } + + // Disable second texture stage, since we're done + IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP, + D3DTOP_DISABLE); + IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP, + D3DTOP_DISABLE); + + // Set an identity world and view matrix + SDL_zero(matrix); + matrix.m[0][0] = 1.0f; + matrix.m[1][1] = 1.0f; + matrix.m[2][2] = 1.0f; + matrix.m[3][3] = 1.0f; + IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix); + IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix); + + // Reset our current scale mode + SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode)); + + // Reset our current address mode + SDL_zeroa(data->addressMode); + + // Start the render with beginScene + data->beginScene = true; +} + +static bool D3D_Reset(SDL_Renderer *renderer); + +static bool D3D_ActivateRenderer(SDL_Renderer *renderer) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + HRESULT result; + + if (data->updateSize) { + SDL_Window *window = renderer->window; + int w, h; + const SDL_DisplayMode *fullscreen_mode = NULL; + + SDL_GetWindowSizeInPixels(window, &w, &h); + data->pparams.BackBufferWidth = w; + data->pparams.BackBufferHeight = h; + if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) { + fullscreen_mode = SDL_GetWindowFullscreenMode(window); + } + if (fullscreen_mode) { + data->pparams.Windowed = FALSE; + data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format); + data->pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate); + } else { + data->pparams.Windowed = TRUE; + data->pparams.BackBufferFormat = D3DFMT_UNKNOWN; + data->pparams.FullScreen_RefreshRateInHz = 0; + } + if (!D3D_Reset(renderer)) { + return false; + } + + data->updateSize = false; + } + if (data->beginScene) { + result = IDirect3DDevice9_BeginScene(data->device); + if (result == D3DERR_DEVICELOST) { + if (!D3D_Reset(renderer)) { + return false; + } + result = IDirect3DDevice9_BeginScene(data->device); + } + if (FAILED(result)) { + return D3D_SetError("BeginScene()", result); + } + data->beginScene = false; + } + return true; +} + +static void D3D_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + + if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { + data->updateSize = 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: + break; + } + return (D3DBLEND)0; +} + +static D3DBLENDOP GetBlendEquation(SDL_BlendOperation operation) +{ + switch (operation) { + case SDL_BLENDOPERATION_ADD: + return D3DBLENDOP_ADD; + case SDL_BLENDOPERATION_SUBTRACT: + return D3DBLENDOP_SUBTRACT; + case SDL_BLENDOPERATION_REV_SUBTRACT: + return D3DBLENDOP_REVSUBTRACT; + case SDL_BLENDOPERATION_MINIMUM: + return D3DBLENDOP_MIN; + case SDL_BLENDOPERATION_MAXIMUM: + return D3DBLENDOP_MAX; + default: + break; + } + return (D3DBLENDOP)0; +} + +static bool D3D_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + 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) || + !GetBlendEquation(colorOperation) || + !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) || + !GetBlendEquation(alphaOperation)) { + return false; + } + + if (!data->enableSeparateAlphaBlend) { + if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) { + return false; + } + } + return true; +} + +static bool D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h) +{ + HRESULT result; + + texture->dirty = false; + texture->w = w; + texture->h = h; + texture->usage = usage; + texture->format = format; + texture->d3dfmt = d3dfmt; + + result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage, + PixelFormatToD3DFMT(format), + D3DPOOL_DEFAULT, &texture->texture, NULL); + if (FAILED(result)) { + return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); + } + return true; +} + +static bool D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture) +{ + HRESULT result; + + if (!texture->staging) { + result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0, + texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL); + if (FAILED(result)) { + return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result); + } + } + return true; +} + +static bool D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture) +{ + if (texture->texture) { + IDirect3DTexture9_Release(texture->texture); + texture->texture = NULL; + } + if (texture->staging) { + IDirect3DTexture9_AddDirtyRect(texture->staging, NULL); + texture->dirty = true; + } + return true; +} + +static bool 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; + const Uint8 *src; + Uint8 *dst; + int row, length; + HRESULT result; + + if (!D3D_CreateStagingTexture(device, texture)) { + return false; + } + + d3drect.left = x; + d3drect.right = (LONG)x + w; + d3drect.top = y; + d3drect.bottom = (LONG)y + h; + + result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0); + if (FAILED(result)) { + return D3D_SetError("LockRect()", result); + } + + src = (const Uint8 *)pixels; + dst = (Uint8 *)locked.pBits; + length = w * SDL_BYTESPERPIXEL(texture->format); + if (length == pitch && length == locked.Pitch) { + SDL_memcpy(dst, src, (size_t)length * h); + } else { + if (length > pitch) { + length = pitch; + } + if (length > locked.Pitch) { + length = locked.Pitch; + } + for (row = 0; row < h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += locked.Pitch; + } + } + result = IDirect3DTexture9_UnlockRect(texture->staging, 0); + if (FAILED(result)) { + return D3D_SetError("UnlockRect()", result); + } + texture->dirty = true; + + return true; +} + +static void D3D_DestroyTextureRep(D3D_TextureRep *texture) +{ + if (texture->texture) { + IDirect3DTexture9_Release(texture->texture); + texture->texture = NULL; + } + if (texture->staging) { + IDirect3DTexture9_Release(texture->staging); + texture->staging = NULL; + } +} + +static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata; + DWORD usage; + + texturedata = (D3D_TextureData *)SDL_calloc(1, sizeof(*texturedata)); + if (!texturedata) { + return false; + } + texturedata->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? D3DTEXF_POINT : D3DTEXF_LINEAR; + + texture->internal = texturedata; + + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + usage = D3DUSAGE_RENDERTARGET; + } else { + usage = 0; + } + + if (!D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) { + return false; + } +#ifdef SDL_HAVE_YUV + if (texture->format == SDL_PIXELFORMAT_YV12 || + texture->format == SDL_PIXELFORMAT_IYUV) { + texturedata->yuv = true; + + if (!D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2)) { + return false; + } + + if (!D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2)) { + return false; + } + + texturedata->shader = SHADER_YUV; + texturedata->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8); + if (texturedata->shader_params == NULL) { + return SDL_SetError("Unsupported YUV colorspace"); + } + } +#endif + return true; +} + +static bool D3D_RecreateTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return true; + } + + if (!D3D_RecreateTextureRep(data->device, &texturedata->texture)) { + return false; + } +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + if (!D3D_RecreateTextureRep(data->device, &texturedata->utexture)) { + return false; + } + + if (!D3D_RecreateTextureRep(data->device, &texturedata->vtexture)) { + return false; + } + } +#endif + return true; +} + +static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, const void *pixels, int pitch) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } + + if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) { + return false; + } +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + // 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, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) { + return false; + } + + // Skip to the correct offset into the next texture + 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)) { + return false; + } + } +#endif + return true; +} + +#ifdef SDL_HAVE_YUV +static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } + + if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch)) { + return false; + } + if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) { + return false; + } + if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) { + return false; + } + return true; +} +#endif + +static bool D3D_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, void **pixels, int *pitch) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + IDirect3DDevice9 *device = data->device; + + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } +#ifdef SDL_HAVE_YUV + texturedata->locked_rect = *rect; + + if (texturedata->yuv) { + // It's more efficient to upload directly... + if (!texturedata->pixels) { + texturedata->pitch = texture->w; + texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2); + if (!texturedata->pixels) { + return false; + } + } + *pixels = + (void *)(texturedata->pixels + rect->y * texturedata->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = texturedata->pitch; + } else +#endif + { + RECT d3drect; + D3DLOCKED_RECT locked; + HRESULT result; + + if (!D3D_CreateStagingTexture(device, &texturedata->texture)) { + return false; + } + + d3drect.left = rect->x; + d3drect.right = (LONG)rect->x + rect->w; + d3drect.top = rect->y; + d3drect.bottom = (LONG)rect->y + rect->h; + + result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0); + if (FAILED(result)) { + return D3D_SetError("LockRect()", result); + } + *pixels = locked.pBits; + *pitch = locked.Pitch; + } + return true; +} + +static void D3D_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return; + } +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + const SDL_Rect *rect = &texturedata->locked_rect; + void *pixels = + (void *)(texturedata->pixels + rect->y * texturedata->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch); + } else +#endif + { + IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0); + texturedata->texture.dirty = true; + if (data->drawstate.texture == texture) { + data->drawstate.texture = NULL; + data->drawstate.shader = SHADER_NONE; + data->drawstate.shader_params = NULL; + IDirect3DDevice9_SetPixelShader(data->device, NULL); + IDirect3DDevice9_SetTexture(data->device, 0, NULL); + } + } +} + +static void D3D_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) +{ + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return; + } + + texturedata->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3DTEXF_POINT : D3DTEXF_LINEAR; +} + +static bool D3D_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3D_TextureData *texturedata; + D3D_TextureRep *texturerep; + HRESULT result; + IDirect3DDevice9 *device = data->device; + + // Release the previous render target if it wasn't the default one + if (data->currentRenderTarget) { + IDirect3DSurface9_Release(data->currentRenderTarget); + data->currentRenderTarget = NULL; + } + + if (!texture) { + IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget); + return true; + } + + texturedata = (D3D_TextureData *)texture->internal; + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } + + // Make sure the render target is updated if it was locked and written to + texturerep = &texturedata->texture; + if (texturerep->dirty && texturerep->staging) { + if (!texturerep->texture) { + result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage, + PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL); + if (FAILED(result)) { + return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); + } + } + + result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture); + if (FAILED(result)) { + return D3D_SetError("UpdateTexture()", result); + } + texturerep->dirty = false; + } + + result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget); + if (FAILED(result)) { + return D3D_SetError("GetSurfaceLevel()", result); + } + result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget); + if (FAILED(result)) { + return D3D_SetError("SetRenderTarget()", result); + } + + return true; +} + +static bool D3D_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) +{ + if (!D3D_ActivateRenderer(renderer)) { + return false; + } + + return D3D_SetRenderTargetInternal(renderer, texture); +} + +static bool D3D_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + return true; // nothing to do in this backend. +} + +static bool D3D_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) +{ + const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.draw.color.r * cmd->data.draw.color_scale, + cmd->data.draw.color.g * cmd->data.draw.color_scale, + cmd->data.draw.color.b * cmd->data.draw.color_scale, + cmd->data.draw.color.a); + const size_t vertslen = count * sizeof(Vertex); + Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first); + int i; + + if (!verts) { + return false; + } + + SDL_memset(verts, '\0', vertslen); + cmd->data.draw.count = count; + + for (i = 0; i < count; i++, verts++, points++) { + verts->x = points->x; + verts->y = points->y; + verts->color = color; + } + + return true; +} + +static bool D3D_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y) +{ + int i; + int count = indices ? num_indices : num_vertices; + Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(Vertex), 0, &cmd->data.draw.first); + const float color_scale = cmd->data.draw.color_scale; + + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + size_indices = indices ? size_indices : 0; + + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_FColor *col_; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char *)xy + j * xy_stride); + col_ = (SDL_FColor *)((char *)color + j * color_stride); + + verts->x = xy_[0] * scale_x - 0.5f; + verts->y = xy_[1] * scale_y - 0.5f; + verts->z = 0.0f; + verts->color = D3DCOLOR_COLORVALUE(col_->r * color_scale, col_->g * color_scale, col_->b * color_scale, col_->a); + + if (texture) { + float *uv_ = (float *)((char *)uv + j * uv_stride); + verts->u = uv_[0]; + verts->v = uv_[1]; + } else { + verts->u = 0.0f; + verts->v = 0.0f; + } + + verts += 1; + } + return true; +} + +static bool UpdateDirtyTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture) +{ + if (texture->dirty && texture->staging) { + HRESULT result; + if (!texture->texture) { + result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage, + PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL); + if (FAILED(result)) { + return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result); + } + } + + result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture); + if (FAILED(result)) { + return D3D_SetError("UpdateTexture()", result); + } + texture->dirty = false; + } + return true; +} + +static bool BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler) +{ + HRESULT result; + UpdateDirtyTexture(device, texture); + result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture); + if (FAILED(result)) { + return D3D_SetError("SetTexture()", result); + } + return true; +} + +static void UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index) +{ + if (texturedata->scaleMode != data->scaleMode[index]) { + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, texturedata->scaleMode); + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, texturedata->scaleMode); + data->scaleMode[index] = texturedata->scaleMode; + } +} + +static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMode addressMode, unsigned index) +{ + if (addressMode != data->addressMode[index]) { + switch (addressMode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + break; + case SDL_TEXTURE_ADDRESS_WRAP: + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); + IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); + break; + default: + break; + } + data->addressMode[index] = addressMode; + } +} + +static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_TextureAddressMode addressMode, D3D9_Shader *shader, const float **shader_params) +{ + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + + if (!texturedata) { + return SDL_SetError("Texture is not currently available"); + } + + UpdateTextureScaleMode(data, texturedata, 0); + UpdateTextureAddressMode(data, addressMode, 0); + + *shader = texturedata->shader; + *shader_params = texturedata->shader_params; + + if (!BindTextureRep(data->device, &texturedata->texture, 0)) { + return false; + } +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + UpdateTextureScaleMode(data, texturedata, 1); + UpdateTextureScaleMode(data, texturedata, 2); + UpdateTextureAddressMode(data, addressMode, 1); + UpdateTextureAddressMode(data, addressMode, 2); + + if (!BindTextureRep(data->device, &texturedata->utexture, 1)) { + return false; + } + if (!BindTextureRep(data->device, &texturedata->vtexture, 2)) { + return false; + } + } +#endif + return true; +} + +static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd) +{ + SDL_Texture *texture = cmd->data.draw.texture; + const SDL_BlendMode blend = cmd->data.draw.blend; + + if (texture != data->drawstate.texture) { +#ifdef SDL_HAVE_YUV + D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *)data->drawstate.texture->internal : NULL; + D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *)texture->internal : NULL; +#endif + D3D9_Shader shader = SHADER_NONE; + const float *shader_params = NULL; + + // disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. + if (!texture) { + IDirect3DDevice9_SetTexture(data->device, 0, NULL); + } +#ifdef SDL_HAVE_YUV + if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) { + IDirect3DDevice9_SetTexture(data->device, 1, NULL); + IDirect3DDevice9_SetTexture(data->device, 2, NULL); + } +#endif + if (texture && !SetupTextureState(data, texture, cmd->data.draw.texture_address_mode, &shader, &shader_params)) { + return false; + } + +#ifdef SDL_HAVE_YUV + if (shader != data->drawstate.shader) { + const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, data->shaders[shader]); + if (FAILED(result)) { + return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result); + } + data->drawstate.shader = shader; + } + + if (shader_params != data->drawstate.shader_params) { + if (shader_params) { + const UINT shader_params_length = 4; // The YUV shader takes 4 float4 parameters + const HRESULT result = IDirect3DDevice9_SetPixelShaderConstantF(data->device, 0, shader_params, shader_params_length); + if (FAILED(result)) { + return D3D_SetError("IDirect3DDevice9_SetPixelShaderConstantF()", result); + } + } + data->drawstate.shader_params = shader_params; + } +#endif // SDL_HAVE_YUV + + data->drawstate.texture = texture; + } else if (texture) { + D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal; + UpdateDirtyTexture(data->device, &texturedata->texture); +#ifdef SDL_HAVE_YUV + if (texturedata->yuv) { + UpdateDirtyTexture(data->device, &texturedata->utexture); + UpdateDirtyTexture(data->device, &texturedata->vtexture); + } +#endif + } + + if (blend != data->drawstate.blend) { + if (blend == SDL_BLENDMODE_NONE) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE); + } else { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND, + GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND, + GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP, + GetBlendEquation(SDL_GetBlendModeColorOperation(blend))); + if (data->enableSeparateAlphaBlend) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA, + GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA, + GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend))); + IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA, + GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend))); + } + } + + data->drawstate.blend = blend; + } + + if (data->drawstate.viewport_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + D3DVIEWPORT9 d3dviewport; + d3dviewport.X = viewport->x; + d3dviewport.Y = viewport->y; + d3dviewport.Width = viewport->w; + d3dviewport.Height = viewport->h; + d3dviewport.MinZ = 0.0f; + d3dviewport.MaxZ = 1.0f; + IDirect3DDevice9_SetViewport(data->device, &d3dviewport); + + // Set an orthographic projection matrix + if (viewport->w && viewport->h) { + D3DMATRIX d3dmatrix; + SDL_zero(d3dmatrix); + d3dmatrix.m[0][0] = 2.0f / viewport->w; + d3dmatrix.m[1][1] = -2.0f / viewport->h; + d3dmatrix.m[2][2] = 1.0f; + d3dmatrix.m[3][0] = -1.0f; + d3dmatrix.m[3][1] = 1.0f; + d3dmatrix.m[3][3] = 1.0f; + IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix); + } + + data->drawstate.viewport_dirty = false; + } + + if (data->drawstate.cliprect_enabled_dirty) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE); + data->drawstate.cliprect_enabled_dirty = false; + } + + if (data->drawstate.cliprect_dirty) { + const SDL_Rect *viewport = &data->drawstate.viewport; + const SDL_Rect *rect = &data->drawstate.cliprect; + RECT d3drect; + d3drect.left = (LONG)viewport->x + rect->x; + d3drect.top = (LONG)viewport->y + rect->y; + d3drect.right = (LONG)viewport->x + rect->x + rect->w; + d3drect.bottom = (LONG)viewport->y + rect->y + rect->h; + IDirect3DDevice9_SetScissorRect(data->device, &d3drect); + data->drawstate.cliprect_dirty = false; + } + + return true; +} + +static void D3D_InvalidateCachedState(SDL_Renderer *renderer) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + data->drawstate.viewport_dirty = true; + data->drawstate.cliprect_enabled_dirty = true; + data->drawstate.cliprect_dirty = true; + data->drawstate.blend = SDL_BLENDMODE_INVALID; + data->drawstate.texture = NULL; + data->drawstate.shader = SHADER_NONE; + data->drawstate.shader_params = NULL; +} + +static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + const int vboidx = data->currentVertexBuffer; + IDirect3DVertexBuffer9 *vbo = NULL; + const bool istarget = renderer->target != NULL; + + if (!D3D_ActivateRenderer(renderer)) { + return false; + } + + if (vertsize > 0) { + // upload the new VBO data for this set of commands. + vbo = data->vertexBuffers[vboidx]; + if (data->vertexBufferSize[vboidx] < vertsize) { + const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY; + const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1; + if (vbo) { + IDirect3DVertexBuffer9_Release(vbo); + } + + if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, (UINT)vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) { + vbo = NULL; + } + data->vertexBuffers[vboidx] = vbo; + data->vertexBufferSize[vboidx] = vbo ? vertsize : 0; + } + + if (vbo) { + void *ptr; + if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, (UINT)vertsize, &ptr, D3DLOCK_DISCARD))) { + vbo = NULL; // oh well, we'll do immediate mode drawing. :( + } else { + SDL_memcpy(ptr, vertices, vertsize); + if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) { + vbo = NULL; // oh well, we'll do immediate mode drawing. :( + } + } + } + + // cycle through a few VBOs so D3D has some time with the data before we replace it. + if (vbo) { + data->currentVertexBuffer++; + if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) { + data->currentVertexBuffer = 0; + } + } else if (!data->reportedVboProblem) { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!"); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method."); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why."); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer."); + data->reportedVboProblem = true; + } + } + + IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof(Vertex)); + + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_SETDRAWCOLOR: + { + /* currently this is sent with each vertex, but if we move to + shaders, we can put this in a uniform here and reduce vertex + buffer bandwidth */ + break; + } + + case SDL_RENDERCMD_SETVIEWPORT: + { + SDL_Rect *viewport = &data->drawstate.viewport; + if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { + SDL_copyp(viewport, &cmd->data.viewport.rect); + data->drawstate.viewport_dirty = true; + data->drawstate.cliprect_dirty = true; + } + break; + } + + case SDL_RENDERCMD_SETCLIPRECT: + { + const SDL_Rect *rect = &cmd->data.cliprect.rect; + if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) { + data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled; + data->drawstate.cliprect_enabled_dirty = true; + } + + if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) { + SDL_copyp(&data->drawstate.cliprect, rect); + data->drawstate.cliprect_dirty = true; + } + break; + } + + case SDL_RENDERCMD_CLEAR: + { + const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.color.color.r * cmd->data.color.color_scale, + cmd->data.color.color.g * cmd->data.color.color_scale, + cmd->data.color.color.b * cmd->data.color.color_scale, + cmd->data.color.color.a); + const SDL_Rect *viewport = &data->drawstate.viewport; + const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth; + const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight; + const bool viewport_equal = ((viewport->x == 0) && (viewport->y == 0) && (viewport->w == backw) && (viewport->h == backh)); + + if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) { + IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE); + data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled; + } + + // Don't reset the viewport if we don't have to! + if (!data->drawstate.viewport_dirty && viewport_equal) { + IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0); + } else { + // Clear is defined to clear the entire render target + D3DVIEWPORT9 wholeviewport = { 0, 0, 0, 0, 0.0f, 1.0f }; + wholeviewport.Width = backw; + wholeviewport.Height = backh; + IDirect3DDevice9_SetViewport(data->device, &wholeviewport); + data->drawstate.viewport_dirty = true; // we still need to (re)set orthographic projection, so always mark it dirty. + IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0); + } + + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: + { + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + SetDrawState(data, cmd); + if (vbo) { + IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(first / sizeof(Vertex)), (UINT)count); + } else { + const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first); + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex)); + } + break; + } + + case SDL_RENDERCMD_DRAW_LINES: + { + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first); + + /* DirectX 9 has the same line rasterization semantics as GDI, + so we need to close the endpoint of the line with a second draw call. + NOLINTNEXTLINE(clang-analyzer-core.NullDereference): FIXME: Can verts truly not be NULL ? */ + const bool close_endpoint = ((count == 2) || (verts[0].x != verts[count - 1].x) || (verts[0].y != verts[count - 1].y)); + + SetDrawState(data, cmd); + + if (vbo) { + IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)(first / sizeof(Vertex)), (UINT)(count - 1)); + if (close_endpoint) { + IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)((first / sizeof(Vertex)) + (count - 1)), 1); + } + } else { + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex)); + if (close_endpoint) { + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count - 1], sizeof(Vertex)); + } + } + break; + } + + case SDL_RENDERCMD_FILL_RECTS: // unused + break; + + case SDL_RENDERCMD_COPY: // unused + break; + + case SDL_RENDERCMD_COPY_EX: // unused + break; + + case SDL_RENDERCMD_GEOMETRY: + { + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + SetDrawState(data, cmd); + if (vbo) { + IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)(first / sizeof(Vertex)), (UINT)count / 3); + } else { + const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first); + IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex)); + } + break; + } + + case SDL_RENDERCMD_NO_OP: + break; + } + + cmd = cmd->next; + } + + return true; +} + +static SDL_Surface *D3D_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + D3DSURFACE_DESC desc; + LPDIRECT3DSURFACE9 backBuffer; + LPDIRECT3DSURFACE9 surface; + RECT d3drect; + D3DLOCKED_RECT locked; + HRESULT result; + SDL_Surface *output; + + if (data->currentRenderTarget) { + backBuffer = data->currentRenderTarget; + } else { + backBuffer = data->defaultRenderTarget; + } + + result = IDirect3DSurface9_GetDesc(backBuffer, &desc); + if (FAILED(result)) { + D3D_SetError("GetDesc()", result); + return NULL; + } + + result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL); + if (FAILED(result)) { + D3D_SetError("CreateOffscreenPlainSurface()", result); + return NULL; + } + + result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface); + if (FAILED(result)) { + IDirect3DSurface9_Release(surface); + D3D_SetError("GetRenderTargetData()", result); + return NULL; + } + + d3drect.left = rect->x; + d3drect.right = (LONG)rect->x + rect->w; + d3drect.top = rect->y; + d3drect.bottom = (LONG)rect->y + rect->h; + + result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY); + if (FAILED(result)) { + IDirect3DSurface9_Release(surface); + D3D_SetError("LockRect()", result); + return NULL; + } + + output = SDL_DuplicatePixels(rect->w, rect->h, D3DFMTToPixelFormat(desc.Format), SDL_COLORSPACE_SRGB, locked.pBits, locked.Pitch); + + IDirect3DSurface9_UnlockRect(surface); + + IDirect3DSurface9_Release(surface); + + return output; +} + +static bool D3D_RenderPresent(SDL_Renderer *renderer) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + HRESULT result; + + if (!data->beginScene) { + IDirect3DDevice9_EndScene(data->device); + data->beginScene = true; + } + + result = IDirect3DDevice9_TestCooperativeLevel(data->device); + if (result == D3DERR_DEVICELOST) { + // We'll reset later + return false; + } + if (result == D3DERR_DEVICENOTRESET) { + D3D_Reset(renderer); + } + result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL); + if (FAILED(result)) { + return D3D_SetError("Present()", result); + } + return true; +} + +static void D3D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D_RenderData *renderdata = (D3D_RenderData *)renderer->internal; + D3D_TextureData *data = (D3D_TextureData *)texture->internal; + + if (renderdata->drawstate.texture == texture) { + renderdata->drawstate.texture = NULL; + renderdata->drawstate.shader = SHADER_NONE; + renderdata->drawstate.shader_params = NULL; + IDirect3DDevice9_SetPixelShader(renderdata->device, NULL); + IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL); +#ifdef SDL_HAVE_YUV + if (data->yuv) { + IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL); + IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL); + } +#endif + } + + if (!data) { + return; + } + + D3D_DestroyTextureRep(&data->texture); +#ifdef SDL_HAVE_YUV + D3D_DestroyTextureRep(&data->utexture); + D3D_DestroyTextureRep(&data->vtexture); + SDL_free(data->pixels); +#endif + SDL_free(data); + texture->internal = NULL; +} + +static void D3D_DestroyRenderer(SDL_Renderer *renderer) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + + if (data) { + int i; + + // Release the render target + if (data->defaultRenderTarget) { + IDirect3DSurface9_Release(data->defaultRenderTarget); + data->defaultRenderTarget = NULL; + } + if (data->currentRenderTarget) { + IDirect3DSurface9_Release(data->currentRenderTarget); + data->currentRenderTarget = NULL; + } +#ifdef SDL_HAVE_YUV + for (i = 0; i < SDL_arraysize(data->shaders); ++i) { + if (data->shaders[i]) { + IDirect3DPixelShader9_Release(data->shaders[i]); + data->shaders[i] = NULL; + } + } +#endif + // Release all vertex buffers + for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { + if (data->vertexBuffers[i]) { + IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]); + } + data->vertexBuffers[i] = NULL; + } + if (data->device) { + IDirect3DDevice9_Release(data->device); + data->device = NULL; + } + if (data->d3d) { + IDirect3D9_Release(data->d3d); + SDL_UnloadObject(data->d3dDLL); + } + SDL_free(data); + } +} + +static bool D3D_Reset(SDL_Renderer *renderer) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + const Float4X4 d3dmatrix = MatrixIdentity(); + HRESULT result; + SDL_Texture *texture; + int i; + + // Cancel any scene that we've started + if (!data->beginScene) { + IDirect3DDevice9_EndScene(data->device); + data->beginScene = true; + } + + // Release the default render target before reset + if (data->defaultRenderTarget) { + IDirect3DSurface9_Release(data->defaultRenderTarget); + data->defaultRenderTarget = NULL; + } + if (data->currentRenderTarget) { + IDirect3DSurface9_Release(data->currentRenderTarget); + data->currentRenderTarget = NULL; + } + + // Release application render targets + for (texture = renderer->textures; texture; texture = texture->next) { + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + D3D_DestroyTexture(renderer, texture); + } else { + D3D_RecreateTexture(renderer, texture); + } + } + + // Release all vertex buffers + for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { + if (data->vertexBuffers[i]) { + IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]); + } + data->vertexBuffers[i] = NULL; + data->vertexBufferSize[i] = 0; + } + + result = IDirect3DDevice9_Reset(data->device, &data->pparams); + if (FAILED(result)) { + if (result == D3DERR_DEVICELOST) { + // Don't worry about it, we'll reset later... + return true; + } else { + return D3D_SetError("Reset()", result); + } + } + + // Allocate application render targets + for (texture = renderer->textures; texture; texture = texture->next) { + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + D3D_CreateTexture(renderer, texture, 0); + } + } + + IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget); + D3D_InitRenderState(data); + D3D_SetRenderTargetInternal(renderer, renderer->target); + + D3D_InvalidateCachedState(renderer); + + IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX *)&d3dmatrix); + + // Let the application know that render targets were reset + { + SDL_Event event; + SDL_zero(event); + event.type = SDL_EVENT_RENDER_TARGETS_RESET; + event.render.windowID = SDL_GetWindowID(SDL_GetRenderWindow(renderer)); + SDL_PushEvent(&event); + } + + return true; +} + +static bool D3D_SetVSync(SDL_Renderer *renderer, const int vsync) +{ + D3D_RenderData *data = (D3D_RenderData *)renderer->internal; + + DWORD PresentationInterval; + switch (vsync) { + case 0: + PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + break; + case 1: + PresentationInterval = D3DPRESENT_INTERVAL_ONE; + break; + case 2: + PresentationInterval = D3DPRESENT_INTERVAL_TWO; + break; + case 3: + PresentationInterval = D3DPRESENT_INTERVAL_THREE; + break; + case 4: + PresentationInterval = D3DPRESENT_INTERVAL_FOUR; + break; + default: + return SDL_Unsupported(); + } + + D3DCAPS9 caps; + HRESULT result = IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); + if (FAILED(result)) { + return D3D_SetError("GetDeviceCaps()", result); + } + if (!(caps.PresentationIntervals & PresentationInterval)) { + return SDL_Unsupported(); + } + data->pparams.PresentationInterval = PresentationInterval; + + if (!D3D_Reset(renderer)) { + // D3D_Reset will call SDL_SetError() + return false; + } + return true; +} + +static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) +{ + D3D_RenderData *data; + HRESULT result; + HWND hwnd; + D3DPRESENT_PARAMETERS pparams; + IDirect3DSwapChain9 *chain; + D3DCAPS9 caps; + DWORD device_flags; + int w, h; + SDL_DisplayID displayID; + const SDL_DisplayMode *fullscreen_mode = NULL; + + hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + if (!hwnd) { + return SDL_SetError("Couldn't get window handle"); + } + + SDL_SetupRendererColorspace(renderer, create_props); + + if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { + return SDL_SetError("Unsupported output colorspace"); + } + + data = (D3D_RenderData *)SDL_calloc(1, sizeof(*data)); + if (!data) { + return false; + } + + if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) { + SDL_free(data); + return SDL_SetError("Unable to create Direct3D interface"); + } + + renderer->WindowEvent = D3D_WindowEvent; + renderer->SupportsBlendMode = D3D_SupportsBlendMode; + renderer->CreateTexture = D3D_CreateTexture; + renderer->UpdateTexture = D3D_UpdateTexture; +#ifdef SDL_HAVE_YUV + renderer->UpdateTextureYUV = D3D_UpdateTextureYUV; +#endif + renderer->LockTexture = D3D_LockTexture; + renderer->UnlockTexture = D3D_UnlockTexture; + renderer->SetTextureScaleMode = D3D_SetTextureScaleMode; + renderer->SetRenderTarget = D3D_SetRenderTarget; + renderer->QueueSetViewport = D3D_QueueNoOp; + renderer->QueueSetDrawColor = D3D_QueueNoOp; + renderer->QueueDrawPoints = D3D_QueueDrawPoints; + renderer->QueueDrawLines = D3D_QueueDrawPoints; // lines and points queue vertices the same way. + renderer->QueueGeometry = D3D_QueueGeometry; + renderer->InvalidateCachedState = D3D_InvalidateCachedState; + renderer->RunCommandQueue = D3D_RunCommandQueue; + renderer->RenderReadPixels = D3D_RenderReadPixels; + renderer->RenderPresent = D3D_RenderPresent; + renderer->DestroyTexture = D3D_DestroyTexture; + renderer->DestroyRenderer = D3D_DestroyRenderer; + renderer->SetVSync = D3D_SetVSync; + renderer->internal = data; + D3D_InvalidateCachedState(renderer); + + renderer->name = D3D_RenderDriver.name; + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + + SDL_GetWindowSizeInPixels(window, &w, &h); + if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) { + fullscreen_mode = SDL_GetWindowFullscreenMode(window); + } + + SDL_zero(pparams); + pparams.hDeviceWindow = hwnd; + pparams.BackBufferWidth = w; + pparams.BackBufferHeight = h; + pparams.BackBufferCount = 1; + pparams.SwapEffect = D3DSWAPEFFECT_DISCARD; + + if (fullscreen_mode) { + pparams.Windowed = FALSE; + pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format); + pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate); + } else { + pparams.Windowed = TRUE; + pparams.BackBufferFormat = D3DFMT_UNKNOWN; + pparams.FullScreen_RefreshRateInHz = 0; + } + pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + // Get the adapter for the display that the window is on + displayID = SDL_GetDisplayForWindow(window); + data->adapter = SDL_GetDirect3D9AdapterIndex(displayID); + + result = IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps); + if (FAILED(result)) { + return D3D_SetError("GetDeviceCaps()", result); + } + + device_flags = D3DCREATE_FPU_PRESERVE; + if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) { + device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; + } else { + device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; + } + + if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, false)) { + device_flags |= D3DCREATE_MULTITHREADED; + } + + result = IDirect3D9_CreateDevice(data->d3d, data->adapter, + D3DDEVTYPE_HAL, + pparams.hDeviceWindow, + device_flags, + &pparams, &data->device); + if (FAILED(result)) { + return D3D_SetError("CreateDevice()", result); + } + + // Get presentation parameters to fill info + result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain); + if (FAILED(result)) { + return D3D_SetError("GetSwapChain()", result); + } + result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams); + if (FAILED(result)) { + IDirect3DSwapChain9_Release(chain); + return D3D_SetError("GetPresentParameters()", result); + } + IDirect3DSwapChain9_Release(chain); + data->pparams = pparams; + + IDirect3DDevice9_GetDeviceCaps(data->device, &caps); + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, SDL_min(caps.MaxTextureWidth, caps.MaxTextureHeight)); + + if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) { + data->enableSeparateAlphaBlend = true; + } + + // Store the default render target + IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget); + data->currentRenderTarget = NULL; + + // Set up parameters for rendering + D3D_InitRenderState(data); +#ifdef SDL_HAVE_YUV + if (caps.MaxSimultaneousTextures >= 3) { + int i; + for (i = SHADER_NONE + 1; 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]) { + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); + } + } +#endif + + SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D9_DEVICE_POINTER, data->device); + + return true; +} + +SDL_RenderDriver D3D_RenderDriver = { + D3D_CreateRenderer, "direct3d" +}; +#endif // SDL_VIDEO_RENDER_D3D diff --git a/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.c b/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.c new file mode 100644 index 0000000..9b1b4b5 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.c @@ -0,0 +1,48 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_D3D + +#include "../../core/windows/SDL_windows.h" + +#include + +#include "SDL_shaders_d3d.h" + +// The shaders here were compiled with compile_shaders.bat + +#define g_ps20_main D3D9_PixelShader_YUV +#include "D3D9_PixelShader_YUV.h" +#undef g_ps20_main + +static const BYTE *D3D9_shaders[] = { + NULL, + D3D9_PixelShader_YUV +}; +SDL_COMPILE_TIME_ASSERT(D3D9_shaders, SDL_arraysize(D3D9_shaders) == NUM_SHADERS); + +HRESULT D3D9_CreatePixelShader(IDirect3DDevice9 *d3dDevice, D3D9_Shader shader, IDirect3DPixelShader9 **pixelShader) +{ + return IDirect3DDevice9_CreatePixelShader(d3dDevice, (const DWORD *)D3D9_shaders[shader], pixelShader); +} + +#endif // SDL_VIDEO_RENDER_D3D diff --git a/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.h b/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.h new file mode 100644 index 0000000..90ef7a9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/SDL_shaders_d3d.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// D3D9 shader implementation + +typedef enum +{ + SHADER_NONE, + SHADER_YUV, + NUM_SHADERS +} D3D9_Shader; + +extern HRESULT D3D9_CreatePixelShader(IDirect3DDevice9 *d3dDevice, D3D9_Shader shader, IDirect3DPixelShader9 **pixelShader); diff --git a/contrib/SDL-3.2.8/src/render/direct3d/compile_shaders.bat b/contrib/SDL-3.2.8/src/render/direct3d/compile_shaders.bat new file mode 100644 index 0000000..81d513e --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d/compile_shaders.bat @@ -0,0 +1 @@ +fxc /T ps_2_0 /Fh D3D9_PixelShader_YUV.h D3D9_PixelShader_YUV.hlsl diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.h b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.h new file mode 100644 index 0000000..a1297c9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.h @@ -0,0 +1,1060 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer Constants +// { +// +// float scRGB_output; // Offset: 0 Size: 4 +// float texture_type; // Offset: 4 Size: 4 +// float input_type; // Offset: 8 Size: 4 +// float color_scale; // Offset: 12 Size: 4 +// float tonemap_method; // Offset: 16 Size: 4 +// float tonemap_factor1; // Offset: 20 Size: 4 +// float tonemap_factor2; // Offset: 24 Size: 4 +// float sdr_white_point; // Offset: 28 Size: 4 +// float4 Yoffset; // Offset: 32 Size: 16 +// float4 Rcoeff; // Offset: 48 Size: 16 +// float4 Gcoeff; // Offset: 64 Size: 16 +// float4 Bcoeff; // Offset: 80 Size: 16 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// sampler0 sampler NA NA s0 1 +// texture0 texture float4 2d t0 1 +// texture1 texture float4 2d t1 1 +// texture2 texture float4 2d t2 1 +// Constants cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// COLOR 0 xyzw 2 NONE float xyzw +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_TARGET 0 xyzw 0 TARGET float xyzw +// +ps_5_0 +dcl_globalFlags refactoringAllowed +dcl_constantbuffer CB0[6], immediateIndexed +dcl_sampler s0, mode_default +dcl_resource_texture2d (float,float,float,float) t0 +dcl_resource_texture2d (float,float,float,float) t1 +dcl_resource_texture2d (float,float,float,float) t2 +dcl_input_ps linear v1.xy +dcl_input_ps linear v2.xyzw +dcl_output o0.xyzw +dcl_temps 7 +eq r0.xyzw, cb0[0].yzzz, l(0.000000, 3.000000, 2.000000, 1.000000) +if_nz r0.x + mov r1.xyzw, l(1.000000,1.000000,1.000000,1.000000) +else + eq r0.x, cb0[0].y, l(1.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r1.xyzw, v1.xyxx, t0.xyzw, s0 + else + eq r0.x, cb0[0].y, l(2.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zxyw, s0 + add r2.xyz, r2.xyzx, cb0[2].xyzx + dp3 r1.x, r2.xyzx, cb0[3].xyzx + dp3 r1.y, r2.xyzx, cb0[4].xyzx + dp3 r1.z, r2.xyzx, cb0[5].xyzx + else + eq r0.x, cb0[0].y, l(3.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.yz, v1.xyxx, t1.zyxw, s0 + add r2.xyz, r2.xyzx, cb0[2].xyzx + dp3 r1.x, r2.xyzx, cb0[3].xyzx + dp3 r1.y, r2.xyzx, cb0[4].xyzx + dp3 r1.z, r2.xyzx, cb0[5].xyzx + else + eq r0.x, cb0[0].y, l(4.000000) + if_nz r0.x + sample_indexable(texture2d)(float,float,float,float) r2.x, v1.xyxx, t0.xyzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.y, v1.xyxx, t1.yxzw, s0 + sample_indexable(texture2d)(float,float,float,float) r2.z, v1.xyxx, t2.yzxw, s0 + add r2.xyz, r2.xyzx, cb0[2].xyzx + dp3 r1.x, r2.xyzx, cb0[3].xyzx + dp3 r1.y, r2.xyzx, cb0[4].xyzx + dp3 r1.z, r2.xyzx, cb0[5].xyzx + else + mov r1.xyz, l(1.000000,0,0,0) + endif + endif + endif + mov r1.w, l(1.000000) + endif +endif +log r2.xyz, |r1.xyzx| +mul r2.xyz, r2.xyzx, l(0.012683, 0.012683, 0.012683, 0.000000) +exp r2.xyz, r2.xyzx +add r3.xyz, r2.xyzx, l(-0.835938, -0.835938, -0.835938, 0.000000) +max r3.xyz, r3.xyzx, l(0.000000, 0.000000, 0.000000, 0.000000) +mad r2.xyz, -r2.xyzx, l(18.687500, 18.687500, 18.687500, 0.000000), l(18.851562, 18.851562, 18.851562, 0.000000) +div r2.xyz, r3.xyzx, r2.xyzx +log r2.xyz, |r2.xyzx| +mul r2.xyz, r2.xyzx, l(6.277395, 6.277395, 6.277395, 0.000000) +exp r2.xyz, r2.xyzx +mul r2.xyz, r2.xyzx, l(10000.000000, 10000.000000, 10000.000000, 0.000000) +div r2.xyz, r2.xyzx, cb0[1].wwww +movc r2.xyz, r0.yyyy, r2.xyzx, r1.xyzx +ne r0.x, cb0[1].x, l(0.000000) +mul r3.xyz, r2.xyzx, cb0[1].yyyy +eq r4.xy, cb0[1].xxxx, l(1.000000, 2.000000, 0.000000, 0.000000) +dp3 r5.x, l(0.627404, 0.329283, 0.043313, 0.000000), r2.xyzx +dp3 r5.y, l(0.069097, 0.919541, 0.011362, 0.000000), r2.xyzx +dp3 r5.z, l(0.016391, 0.088013, 0.895595, 0.000000), r2.xyzx +movc r5.xyz, r0.zzzz, r5.xyzx, r2.xyzx +max r2.w, r5.z, r5.y +max r2.w, r2.w, r5.x +lt r3.w, l(0.000000), r2.w +mad r4.zw, cb0[1].yyyz, r2.wwww, l(0.000000, 0.000000, 1.000000, 1.000000) +div r2.w, r4.z, r4.w +mul r6.xyz, r2.wwww, r5.xyzx +movc r5.xyz, r3.wwww, r6.xyzx, r5.xyzx +dp3 r6.x, l(1.660496, -0.587656, -0.072840, 0.000000), r5.xyzx +dp3 r6.y, l(-0.124547, 1.132895, -0.008348, 0.000000), r5.xyzx +dp3 r6.z, l(-0.018154, -0.100597, 1.118751, 0.000000), r5.xyzx +movc r5.xyz, r0.zzzz, r6.xyzx, r5.xyzx +movc r4.yzw, r4.yyyy, r5.xxyz, r2.xxyz +movc r3.xyz, r4.xxxx, r3.xyzx, r4.yzwy +movc r2.xyz, r0.xxxx, r3.xyzx, r2.xyzx +if_nz r0.w + ne r0.x, l(0.000000, 0.000000, 0.000000, 0.000000), cb0[0].x + if_nz r0.x + ge r3.xyz, l(0.040450, 0.040450, 0.040450, 0.000000), r2.xyzx + mul r4.xyz, r2.xyzx, l(0.077399, 0.077399, 0.077399, 0.000000) + add r5.xyz, r2.xyzx, l(0.055000, 0.055000, 0.055000, 0.000000) + mul r5.xyz, |r5.xyzx|, l(0.947867, 0.947867, 0.947867, 0.000000) + log r5.xyz, r5.xyzx + mul r5.xyz, r5.xyzx, l(2.400000, 2.400000, 2.400000, 0.000000) + exp r5.xyz, r5.xyzx + movc r2.xyz, r3.xyzx, r4.xyzx, r5.xyzx + endif + mul r1.xyz, r2.xyzx, cb0[0].wwww +else + if_nz r0.z + mul r1.xyz, r2.xyzx, cb0[0].wwww + ne r0.x, l(0.000000, 0.000000, 0.000000, 0.000000), cb0[0].x + if_z r0.x + ge r0.xzw, l(0.003131, 0.000000, 0.003131, 0.003131), r1.xxyz + mul r3.xyz, r1.xyzx, l(12.920000, 12.920000, 12.920000, 0.000000) + log r4.xyz, |r1.xyzx| + mul r4.xyz, r4.xyzx, l(0.416667, 0.416667, 0.416667, 0.000000) + exp r4.xyz, r4.xyzx + mad r4.xyz, r4.xyzx, l(1.055000, 1.055000, 1.055000, 0.000000), l(-0.055000, -0.055000, -0.055000, 0.000000) + movc_sat r1.xyz, r0.xzwx, r3.xyzx, r4.xyzx + endif + else + if_nz r0.y + dp3 r0.x, l(1.660496, -0.587656, -0.072840, 0.000000), r2.xyzx + dp3 r0.y, l(-0.124547, 1.132895, -0.008348, 0.000000), r2.xyzx + dp3 r0.z, l(-0.018154, -0.100597, 1.118751, 0.000000), r2.xyzx + mul r1.xyz, r0.xyzx, cb0[0].wwww + ne r0.x, l(0.000000, 0.000000, 0.000000, 0.000000), cb0[0].x + if_z r0.x + ge r0.xyz, l(0.003131, 0.003131, 0.003131, 0.000000), r1.xyzx + mul r3.xyz, r1.xyzx, l(12.920000, 12.920000, 12.920000, 0.000000) + log r4.xyz, |r1.xyzx| + mul r4.xyz, r4.xyzx, l(0.416667, 0.416667, 0.416667, 0.000000) + exp r4.xyz, r4.xyzx + mad r4.xyz, r4.xyzx, l(1.055000, 1.055000, 1.055000, 0.000000), l(-0.055000, -0.055000, -0.055000, 0.000000) + movc_sat r1.xyz, r0.xyzx, r3.xyzx, r4.xyzx + endif + else + mul r1.xyz, r2.xyzx, cb0[0].wwww + endif + endif +endif +mul o0.xyzw, r1.xyzw, v2.xyzw +ret +// Approximately 126 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 154, 200, + 28, 25, 30, 140, 0, 183, + 251, 32, 6, 185, 210, 29, + 251, 110, 1, 0, 0, 0, + 64, 20, 0, 0, 5, 0, + 0, 0, 52, 0, 0, 0, + 80, 4, 0, 0, 196, 4, + 0, 0, 248, 4, 0, 0, + 164, 19, 0, 0, 82, 68, + 69, 70, 20, 4, 0, 0, + 1, 0, 0, 0, 12, 1, + 0, 0, 5, 0, 0, 0, + 60, 0, 0, 0, 0, 5, + 255, 255, 0, 1, 0, 0, + 233, 3, 0, 0, 82, 68, + 49, 49, 60, 0, 0, 0, + 24, 0, 0, 0, 32, 0, + 0, 0, 40, 0, 0, 0, + 36, 0, 0, 0, 12, 0, + 0, 0, 0, 0, 0, 0, + 220, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 229, 0, 0, 0, + 2, 0, 0, 0, 5, 0, + 0, 0, 4, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 1, 0, 0, 0, + 13, 0, 0, 0, 238, 0, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 1, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 247, 0, 0, 0, 2, 0, + 0, 0, 5, 0, 0, 0, + 4, 0, 0, 0, 255, 255, + 255, 255, 2, 0, 0, 0, + 1, 0, 0, 0, 13, 0, + 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 115, 97, + 109, 112, 108, 101, 114, 48, + 0, 116, 101, 120, 116, 117, + 114, 101, 48, 0, 116, 101, + 120, 116, 117, 114, 101, 49, + 0, 116, 101, 120, 116, 117, + 114, 101, 50, 0, 67, 111, + 110, 115, 116, 97, 110, 116, + 115, 0, 171, 171, 0, 1, + 0, 0, 12, 0, 0, 0, + 36, 1, 0, 0, 96, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 3, + 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 24, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 60, 3, 0, 0, + 4, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 24, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 73, 3, 0, 0, 8, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 24, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 84, 3, + 0, 0, 12, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 24, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 96, 3, 0, 0, + 16, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 24, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 111, 3, 0, 0, 20, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 24, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 127, 3, + 0, 0, 24, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 24, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 143, 3, 0, 0, + 28, 0, 0, 0, 4, 0, + 0, 0, 2, 0, 0, 0, + 24, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 159, 3, 0, 0, 32, 0, + 0, 0, 16, 0, 0, 0, + 2, 0, 0, 0, 176, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 212, 3, + 0, 0, 48, 0, 0, 0, + 16, 0, 0, 0, 2, 0, + 0, 0, 176, 3, 0, 0, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 219, 3, 0, 0, + 64, 0, 0, 0, 16, 0, + 0, 0, 2, 0, 0, 0, + 176, 3, 0, 0, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 255, 255, + 255, 255, 0, 0, 0, 0, + 226, 3, 0, 0, 80, 0, + 0, 0, 16, 0, 0, 0, + 2, 0, 0, 0, 176, 3, + 0, 0, 0, 0, 0, 0, + 255, 255, 255, 255, 0, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 115, 99, + 82, 71, 66, 95, 111, 117, + 116, 112, 117, 116, 0, 102, + 108, 111, 97, 116, 0, 171, + 0, 0, 3, 0, 1, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 17, 3, 0, 0, + 116, 101, 120, 116, 117, 114, + 101, 95, 116, 121, 112, 101, + 0, 105, 110, 112, 117, 116, + 95, 116, 121, 112, 101, 0, + 99, 111, 108, 111, 114, 95, + 115, 99, 97, 108, 101, 0, + 116, 111, 110, 101, 109, 97, + 112, 95, 109, 101, 116, 104, + 111, 100, 0, 116, 111, 110, + 101, 109, 97, 112, 95, 102, + 97, 99, 116, 111, 114, 49, + 0, 116, 111, 110, 101, 109, + 97, 112, 95, 102, 97, 99, + 116, 111, 114, 50, 0, 115, + 100, 114, 95, 119, 104, 105, + 116, 101, 95, 112, 111, 105, + 110, 116, 0, 89, 111, 102, + 102, 115, 101, 116, 0, 102, + 108, 111, 97, 116, 52, 0, + 171, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 167, 3, + 0, 0, 82, 99, 111, 101, + 102, 102, 0, 71, 99, 111, + 101, 102, 102, 0, 66, 99, + 111, 101, 102, 102, 0, 77, + 105, 99, 114, 111, 115, 111, + 102, 116, 32, 40, 82, 41, + 32, 72, 76, 83, 76, 32, + 83, 104, 97, 100, 101, 114, + 32, 67, 111, 109, 112, 105, + 108, 101, 114, 32, 49, 48, + 46, 49, 0, 171, 171, 171, + 73, 83, 71, 78, 108, 0, + 0, 0, 3, 0, 0, 0, + 8, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 92, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 1, 0, 0, 0, + 3, 3, 0, 0, 101, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 2, 0, 0, 0, + 15, 15, 0, 0, 83, 86, + 95, 80, 79, 83, 73, 84, + 73, 79, 78, 0, 84, 69, + 88, 67, 79, 79, 82, 68, + 0, 67, 79, 76, 79, 82, + 0, 171, 79, 83, 71, 78, + 44, 0, 0, 0, 1, 0, + 0, 0, 8, 0, 0, 0, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 84, 65, 82, + 71, 69, 84, 0, 171, 171, + 83, 72, 69, 88, 164, 14, + 0, 0, 80, 0, 0, 0, + 169, 3, 0, 0, 106, 8, + 0, 1, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 6, 0, 0, 0, + 90, 0, 0, 3, 0, 96, + 16, 0, 0, 0, 0, 0, + 88, 24, 0, 4, 0, 112, + 16, 0, 0, 0, 0, 0, + 85, 85, 0, 0, 88, 24, + 0, 4, 0, 112, 16, 0, + 1, 0, 0, 0, 85, 85, + 0, 0, 88, 24, 0, 4, + 0, 112, 16, 0, 2, 0, + 0, 0, 85, 85, 0, 0, + 98, 16, 0, 3, 50, 16, + 16, 0, 1, 0, 0, 0, + 98, 16, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 101, 0, 0, 3, 242, 32, + 16, 0, 0, 0, 0, 0, + 104, 0, 0, 2, 7, 0, + 0, 0, 24, 0, 0, 11, + 242, 0, 16, 0, 0, 0, + 0, 0, 150, 138, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 64, 64, 0, 0, 0, 64, + 0, 0, 128, 63, 31, 0, + 4, 3, 10, 0, 16, 0, + 0, 0, 0, 0, 54, 0, + 0, 8, 242, 0, 16, 0, + 1, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 0, 0, + 128, 63, 0, 0, 128, 63, + 18, 0, 0, 1, 24, 0, + 0, 8, 18, 0, 16, 0, + 0, 0, 0, 0, 26, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 31, 0, 4, 3, 10, 0, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 242, 0, 16, 0, 1, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 70, 126, + 16, 0, 0, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 18, 0, 0, 1, + 24, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 26, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 64, 31, 0, 4, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 18, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 98, 0, + 16, 0, 2, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 38, 125, 16, 0, + 1, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 16, 0, 0, 8, + 18, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 16, 0, + 0, 8, 34, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 16, 0, 0, 8, 66, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 5, 0, + 0, 0, 18, 0, 0, 1, + 24, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 26, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 64, 64, 31, 0, 4, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 18, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 98, 0, + 16, 0, 2, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 102, 124, 16, 0, + 1, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 0, 0, 0, 8, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 16, 0, 0, 8, + 18, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 16, 0, + 0, 8, 34, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 16, 0, 0, 8, 66, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 5, 0, + 0, 0, 18, 0, 0, 1, + 24, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 26, 128, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 128, 64, 31, 0, 4, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 69, 0, 0, 139, + 194, 0, 0, 128, 67, 85, + 21, 0, 18, 0, 16, 0, + 2, 0, 0, 0, 70, 16, + 16, 0, 1, 0, 0, 0, + 70, 126, 16, 0, 0, 0, + 0, 0, 0, 96, 16, 0, + 0, 0, 0, 0, 69, 0, + 0, 139, 194, 0, 0, 128, + 67, 85, 21, 0, 34, 0, + 16, 0, 2, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 22, 126, 16, 0, + 1, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 69, 0, 0, 139, 194, 0, + 0, 128, 67, 85, 21, 0, + 66, 0, 16, 0, 2, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 150, 124, + 16, 0, 2, 0, 0, 0, + 0, 96, 16, 0, 0, 0, + 0, 0, 0, 0, 0, 8, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 16, 0, + 0, 8, 18, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 70, 130, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 16, 0, 0, 8, 34, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 70, 130, 32, 0, + 0, 0, 0, 0, 4, 0, + 0, 0, 16, 0, 0, 8, + 66, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 130, + 32, 0, 0, 0, 0, 0, + 5, 0, 0, 0, 18, 0, + 0, 1, 54, 0, 0, 8, + 114, 0, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 128, 63, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 21, 0, + 0, 1, 21, 0, 0, 1, + 21, 0, 0, 1, 54, 0, + 0, 5, 130, 0, 16, 0, + 1, 0, 0, 0, 1, 64, + 0, 0, 0, 0, 128, 63, + 21, 0, 0, 1, 21, 0, + 0, 1, 47, 0, 0, 6, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 128, + 129, 0, 0, 0, 1, 0, + 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 172, 205, 79, 60, + 172, 205, 79, 60, 172, 205, + 79, 60, 0, 0, 0, 0, + 25, 0, 0, 5, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 0, 0, 0, 10, + 114, 0, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 86, 191, + 0, 0, 86, 191, 0, 0, + 86, 191, 0, 0, 0, 0, + 52, 0, 0, 10, 114, 0, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 50, 0, + 0, 16, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 128, 65, 0, 0, 0, + 2, 0, 0, 0, 2, 64, + 0, 0, 0, 128, 149, 65, + 0, 128, 149, 65, 0, 128, + 149, 65, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 208, + 150, 65, 0, 208, 150, 65, + 0, 208, 150, 65, 0, 0, + 0, 0, 14, 0, 0, 7, + 114, 0, 16, 0, 2, 0, + 0, 0, 70, 2, 16, 0, + 3, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 47, 0, 0, 6, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 128, 129, 0, + 0, 0, 2, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 107, 224, 200, 64, 107, 224, + 200, 64, 107, 224, 200, 64, + 0, 0, 0, 0, 25, 0, + 0, 5, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 0, 64, 28, 70, 0, 64, + 28, 70, 0, 64, 28, 70, + 0, 0, 0, 0, 14, 0, + 0, 8, 114, 0, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 246, 143, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 2, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 1, 0, 0, 0, + 57, 0, 0, 8, 18, 0, + 16, 0, 0, 0, 0, 0, + 10, 128, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 64, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 8, + 114, 0, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 86, 133, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 24, 0, + 0, 11, 50, 0, 16, 0, + 4, 0, 0, 0, 6, 128, + 32, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 2, 64, + 0, 0, 0, 0, 128, 63, + 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 16, 0, 0, 10, 18, 0, + 16, 0, 5, 0, 0, 0, + 2, 64, 0, 0, 140, 157, + 32, 63, 200, 151, 168, 62, + 249, 104, 49, 61, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 16, 0, + 0, 10, 34, 0, 16, 0, + 5, 0, 0, 0, 2, 64, + 0, 0, 186, 130, 141, 61, + 10, 103, 107, 63, 175, 39, + 58, 60, 0, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 16, 0, 0, 10, + 66, 0, 16, 0, 5, 0, + 0, 0, 2, 64, 0, 0, + 107, 70, 134, 60, 41, 64, + 180, 61, 183, 69, 101, 63, + 0, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 5, 0, 0, 0, + 166, 10, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 52, 0, 0, 7, 130, 0, + 16, 0, 2, 0, 0, 0, + 42, 0, 16, 0, 5, 0, + 0, 0, 26, 0, 16, 0, + 5, 0, 0, 0, 52, 0, + 0, 7, 130, 0, 16, 0, + 2, 0, 0, 0, 58, 0, + 16, 0, 2, 0, 0, 0, + 10, 0, 16, 0, 5, 0, + 0, 0, 49, 0, 0, 7, + 130, 0, 16, 0, 3, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 0, 0, 58, 0, + 16, 0, 2, 0, 0, 0, + 50, 0, 0, 13, 194, 0, + 16, 0, 4, 0, 0, 0, + 86, 137, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 246, 15, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 128, 63, + 0, 0, 128, 63, 14, 0, + 0, 7, 130, 0, 16, 0, + 2, 0, 0, 0, 42, 0, + 16, 0, 4, 0, 0, 0, + 58, 0, 16, 0, 4, 0, + 0, 0, 56, 0, 0, 7, + 114, 0, 16, 0, 6, 0, + 0, 0, 246, 15, 16, 0, + 2, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 5, 0, 0, 0, + 246, 15, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 6, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 16, 0, 0, 10, 18, 0, + 16, 0, 6, 0, 0, 0, + 2, 64, 0, 0, 34, 139, + 212, 63, 160, 112, 22, 191, + 35, 45, 149, 189, 0, 0, + 0, 0, 70, 2, 16, 0, + 5, 0, 0, 0, 16, 0, + 0, 10, 34, 0, 16, 0, + 6, 0, 0, 0, 2, 64, + 0, 0, 127, 18, 255, 189, + 180, 2, 145, 63, 13, 198, + 8, 188, 0, 0, 0, 0, + 70, 2, 16, 0, 5, 0, + 0, 0, 16, 0, 0, 10, + 66, 0, 16, 0, 6, 0, + 0, 0, 2, 64, 0, 0, + 179, 183, 148, 188, 205, 5, + 206, 189, 60, 51, 143, 63, + 0, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 5, 0, 0, 0, + 166, 10, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, + 6, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 226, 0, + 16, 0, 4, 0, 0, 0, + 86, 5, 16, 0, 4, 0, + 0, 0, 6, 9, 16, 0, + 5, 0, 0, 0, 6, 9, + 16, 0, 2, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 3, 0, 0, 0, + 6, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 3, 0, 0, 0, 150, 7, + 16, 0, 4, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 2, 0, 0, 0, + 6, 0, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, + 3, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 31, 0, 4, 3, 58, 0, + 16, 0, 0, 0, 0, 0, + 57, 0, 0, 11, 18, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 31, 0, 4, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 29, 0, 0, 10, + 114, 0, 16, 0, 3, 0, + 0, 0, 2, 64, 0, 0, + 230, 174, 37, 61, 230, 174, + 37, 61, 230, 174, 37, 61, + 0, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 2, 64, 0, 0, + 145, 131, 158, 61, 145, 131, + 158, 61, 145, 131, 158, 61, + 0, 0, 0, 0, 0, 0, + 0, 10, 114, 0, 16, 0, + 5, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 2, 64, 0, 0, 174, 71, + 97, 61, 174, 71, 97, 61, + 174, 71, 97, 61, 0, 0, + 0, 0, 56, 0, 0, 11, + 114, 0, 16, 0, 5, 0, + 0, 0, 70, 2, 16, 128, + 129, 0, 0, 0, 5, 0, + 0, 0, 2, 64, 0, 0, + 111, 167, 114, 63, 111, 167, + 114, 63, 111, 167, 114, 63, + 0, 0, 0, 0, 47, 0, + 0, 5, 114, 0, 16, 0, + 5, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 5, 0, 0, 0, + 70, 2, 16, 0, 5, 0, + 0, 0, 2, 64, 0, 0, + 154, 153, 25, 64, 154, 153, + 25, 64, 154, 153, 25, 64, + 0, 0, 0, 0, 25, 0, + 0, 5, 114, 0, 16, 0, + 5, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 55, 0, 0, 9, 114, 0, + 16, 0, 2, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 5, 0, 0, 0, + 21, 0, 0, 1, 56, 0, + 0, 8, 114, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 246, 143, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 18, 0, 0, 1, 31, 0, + 4, 3, 42, 0, 16, 0, + 0, 0, 0, 0, 56, 0, + 0, 8, 114, 0, 16, 0, + 1, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 246, 143, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 57, 0, 0, 11, 18, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 10, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 31, 0, 0, 3, + 10, 0, 16, 0, 0, 0, + 0, 0, 29, 0, 0, 10, + 210, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 28, 46, 77, 59, 0, 0, + 0, 0, 28, 46, 77, 59, + 28, 46, 77, 59, 6, 9, + 16, 0, 1, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 3, 0, 0, 0, + 70, 2, 16, 0, 1, 0, + 0, 0, 2, 64, 0, 0, + 82, 184, 78, 65, 82, 184, + 78, 65, 82, 184, 78, 65, + 0, 0, 0, 0, 47, 0, + 0, 6, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 128, 129, 0, 0, 0, + 1, 0, 0, 0, 56, 0, + 0, 10, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 2, 64, 0, 0, 85, 85, + 213, 62, 85, 85, 213, 62, + 85, 85, 213, 62, 0, 0, + 0, 0, 25, 0, 0, 5, + 114, 0, 16, 0, 4, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 50, 0, + 0, 15, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 2, 64, 0, 0, 61, 10, + 135, 63, 61, 10, 135, 63, + 61, 10, 135, 63, 0, 0, + 0, 0, 2, 64, 0, 0, + 174, 71, 97, 189, 174, 71, + 97, 189, 174, 71, 97, 189, + 0, 0, 0, 0, 55, 32, + 0, 9, 114, 0, 16, 0, + 1, 0, 0, 0, 134, 3, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 4, 0, 0, 0, 21, 0, + 0, 1, 18, 0, 0, 1, + 31, 0, 4, 3, 26, 0, + 16, 0, 0, 0, 0, 0, + 16, 0, 0, 10, 18, 0, + 16, 0, 0, 0, 0, 0, + 2, 64, 0, 0, 34, 139, + 212, 63, 160, 112, 22, 191, + 35, 45, 149, 189, 0, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 16, 0, + 0, 10, 34, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 127, 18, 255, 189, + 180, 2, 145, 63, 13, 198, + 8, 188, 0, 0, 0, 0, + 70, 2, 16, 0, 2, 0, + 0, 0, 16, 0, 0, 10, + 66, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 179, 183, 148, 188, 205, 5, + 206, 189, 60, 51, 143, 63, + 0, 0, 0, 0, 70, 2, + 16, 0, 2, 0, 0, 0, + 56, 0, 0, 8, 114, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 0, 0, + 0, 0, 246, 143, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 57, 0, 0, 11, + 18, 0, 16, 0, 0, 0, + 0, 0, 2, 64, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 128, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 0, + 0, 3, 10, 0, 16, 0, + 0, 0, 0, 0, 29, 0, + 0, 10, 114, 0, 16, 0, + 0, 0, 0, 0, 2, 64, + 0, 0, 28, 46, 77, 59, + 28, 46, 77, 59, 28, 46, + 77, 59, 0, 0, 0, 0, + 70, 2, 16, 0, 1, 0, + 0, 0, 56, 0, 0, 10, + 114, 0, 16, 0, 3, 0, + 0, 0, 70, 2, 16, 0, + 1, 0, 0, 0, 2, 64, + 0, 0, 82, 184, 78, 65, + 82, 184, 78, 65, 82, 184, + 78, 65, 0, 0, 0, 0, + 47, 0, 0, 6, 114, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 128, 129, 0, + 0, 0, 1, 0, 0, 0, + 56, 0, 0, 10, 114, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 85, 85, 213, 62, 85, 85, + 213, 62, 85, 85, 213, 62, + 0, 0, 0, 0, 25, 0, + 0, 5, 114, 0, 16, 0, + 4, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 50, 0, 0, 15, 114, 0, + 16, 0, 4, 0, 0, 0, + 70, 2, 16, 0, 4, 0, + 0, 0, 2, 64, 0, 0, + 61, 10, 135, 63, 61, 10, + 135, 63, 61, 10, 135, 63, + 0, 0, 0, 0, 2, 64, + 0, 0, 174, 71, 97, 189, + 174, 71, 97, 189, 174, 71, + 97, 189, 0, 0, 0, 0, + 55, 32, 0, 9, 114, 0, + 16, 0, 1, 0, 0, 0, + 70, 2, 16, 0, 0, 0, + 0, 0, 70, 2, 16, 0, + 3, 0, 0, 0, 70, 2, + 16, 0, 4, 0, 0, 0, + 21, 0, 0, 1, 18, 0, + 0, 1, 56, 0, 0, 8, + 114, 0, 16, 0, 1, 0, + 0, 0, 70, 2, 16, 0, + 2, 0, 0, 0, 246, 143, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 21, 0, + 0, 1, 21, 0, 0, 1, + 21, 0, 0, 1, 56, 0, + 0, 7, 242, 32, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 70, 30, 16, 0, 2, 0, + 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 148, 0, + 0, 0, 126, 0, 0, 0, + 7, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 71, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 11, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 10, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.hlsl b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.hlsl new file mode 100644 index 0000000..aad7b77 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Advanced.hlsl @@ -0,0 +1,7 @@ + +#include "D3D11_PixelShader_Common.hlsli" + +float4 main(PixelShaderInput input) : SV_TARGET +{ + return AdvancedPixelShader(input); +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.h b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.h new file mode 100644 index 0000000..6658e4d --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.h @@ -0,0 +1,284 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer Constants +// { +// +// float scRGB_output; // Offset: 0 Size: 4 [unused] +// float texture_type; // Offset: 4 Size: 4 [unused] +// float input_type; // Offset: 8 Size: 4 [unused] +// float color_scale; // Offset: 12 Size: 4 +// float tonemap_method; // Offset: 16 Size: 4 [unused] +// float tonemap_factor1; // Offset: 20 Size: 4 [unused] +// float tonemap_factor2; // Offset: 24 Size: 4 [unused] +// float sdr_white_point; // Offset: 28 Size: 4 [unused] +// float4 Yoffset; // Offset: 32 Size: 16 [unused] +// float4 Rcoeff; // Offset: 48 Size: 16 [unused] +// float4 Gcoeff; // Offset: 64 Size: 16 [unused] +// float4 Bcoeff; // Offset: 80 Size: 16 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// Constants cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float +// COLOR 0 xyzw 2 NONE float xyzw +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_TARGET 0 xyzw 0 TARGET float xyzw +// +// +// Constant buffer to DX9 shader constant mappings: +// +// Target Reg Buffer Start Reg # of Regs Data Conversion +// ---------- ------- --------- --------- ---------------------- +// c0 cb0 0 1 ( FLT, FLT, FLT, FLT) +// +// +// Level9 shader bytecode: +// + ps_2_0 + dcl t1 + mul r0.xyz, t1, c0.w + mov r0.w, t1.w + mov oC0, r0 + +// approximately 3 instruction slots used +ps_4_0 +dcl_constantbuffer CB0[1], immediateIndexed +dcl_input_ps linear v2.xyzw +dcl_output o0.xyzw +dcl_temps 1 +mov r0.x, cb0[0].w +mov r0.w, l(1.000000) +mul o0.xyzw, r0.xxxw, v2.xyzw +ret +// Approximately 4 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 78, 223, + 23, 23, 93, 184, 255, 26, + 153, 0, 220, 179, 25, 194, + 30, 249, 1, 0, 0, 0, + 192, 4, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 172, 0, 0, 0, 56, 1, + 0, 0, 180, 1, 0, 0, + 24, 4, 0, 0, 140, 4, + 0, 0, 65, 111, 110, 57, + 108, 0, 0, 0, 108, 0, + 0, 0, 0, 2, 255, 255, + 60, 0, 0, 0, 48, 0, + 0, 0, 1, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 48, 0, 0, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 2, + 255, 255, 31, 0, 0, 2, + 0, 0, 0, 128, 1, 0, + 15, 176, 5, 0, 0, 3, + 0, 0, 7, 128, 1, 0, + 228, 176, 0, 0, 255, 160, + 1, 0, 0, 2, 0, 0, + 8, 128, 1, 0, 255, 176, + 1, 0, 0, 2, 0, 8, + 15, 128, 0, 0, 228, 128, + 255, 255, 0, 0, 83, 72, + 68, 82, 132, 0, 0, 0, + 64, 0, 0, 0, 33, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 98, 16, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 101, 0, 0, 3, 242, 32, + 16, 0, 0, 0, 0, 0, + 104, 0, 0, 2, 1, 0, + 0, 0, 54, 0, 0, 6, + 18, 0, 16, 0, 0, 0, + 0, 0, 58, 128, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 54, 0, 0, 5, + 130, 0, 16, 0, 0, 0, + 0, 0, 1, 64, 0, 0, + 0, 0, 128, 63, 56, 0, + 0, 7, 242, 32, 16, 0, + 0, 0, 0, 0, 6, 12, + 16, 0, 0, 0, 0, 0, + 70, 30, 16, 0, 2, 0, + 0, 0, 62, 0, 0, 1, + 83, 84, 65, 84, 116, 0, + 0, 0, 4, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 82, 68, + 69, 70, 92, 2, 0, 0, + 1, 0, 0, 0, 72, 0, + 0, 0, 1, 0, 0, 0, + 28, 0, 0, 0, 0, 4, + 255, 255, 0, 1, 0, 0, + 49, 2, 0, 0, 60, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 0, + 67, 111, 110, 115, 116, 97, + 110, 116, 115, 0, 171, 171, + 60, 0, 0, 0, 12, 0, + 0, 0, 96, 0, 0, 0, + 96, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 128, 1, 0, 0, 0, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 160, 1, 0, 0, 4, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 173, 1, 0, 0, 8, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 184, 1, 0, 0, 12, 0, + 0, 0, 4, 0, 0, 0, + 2, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 196, 1, 0, 0, 16, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 211, 1, 0, 0, 20, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 227, 1, 0, 0, 24, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 243, 1, 0, 0, 28, 0, + 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 144, 1, + 0, 0, 0, 0, 0, 0, + 3, 2, 0, 0, 32, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 12, 2, + 0, 0, 0, 0, 0, 0, + 28, 2, 0, 0, 48, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 12, 2, + 0, 0, 0, 0, 0, 0, + 35, 2, 0, 0, 64, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 12, 2, + 0, 0, 0, 0, 0, 0, + 42, 2, 0, 0, 80, 0, + 0, 0, 16, 0, 0, 0, + 0, 0, 0, 0, 12, 2, + 0, 0, 0, 0, 0, 0, + 115, 99, 82, 71, 66, 95, + 111, 117, 116, 112, 117, 116, + 0, 171, 171, 171, 0, 0, + 3, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 116, 101, 120, 116, + 117, 114, 101, 95, 116, 121, + 112, 101, 0, 105, 110, 112, + 117, 116, 95, 116, 121, 112, + 101, 0, 99, 111, 108, 111, + 114, 95, 115, 99, 97, 108, + 101, 0, 116, 111, 110, 101, + 109, 97, 112, 95, 109, 101, + 116, 104, 111, 100, 0, 116, + 111, 110, 101, 109, 97, 112, + 95, 102, 97, 99, 116, 111, + 114, 49, 0, 116, 111, 110, + 101, 109, 97, 112, 95, 102, + 97, 99, 116, 111, 114, 50, + 0, 115, 100, 114, 95, 119, + 104, 105, 116, 101, 95, 112, + 111, 105, 110, 116, 0, 89, + 111, 102, 102, 115, 101, 116, + 0, 171, 1, 0, 3, 0, + 1, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 82, 99, 111, 101, 102, 102, + 0, 71, 99, 111, 101, 102, + 102, 0, 66, 99, 111, 101, + 102, 102, 0, 77, 105, 99, + 114, 111, 115, 111, 102, 116, + 32, 40, 82, 41, 32, 72, + 76, 83, 76, 32, 83, 104, + 97, 100, 101, 114, 32, 67, + 111, 109, 112, 105, 108, 101, + 114, 32, 49, 48, 46, 49, + 0, 171, 171, 171, 73, 83, + 71, 78, 108, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 92, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 0, + 0, 0, 101, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 2, 0, 0, 0, 15, 15, + 0, 0, 83, 86, 95, 80, + 79, 83, 73, 84, 73, 79, + 78, 0, 84, 69, 88, 67, + 79, 79, 82, 68, 0, 67, + 79, 76, 79, 82, 0, 171, + 79, 83, 71, 78, 44, 0, + 0, 0, 1, 0, 0, 0, + 8, 0, 0, 0, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, + 15, 0, 0, 0, 83, 86, + 95, 84, 65, 82, 71, 69, + 84, 0, 171, 171 +}; diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.hlsl b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.hlsl new file mode 100644 index 0000000..5757491 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Colors.hlsl @@ -0,0 +1,7 @@ + +#include "D3D11_PixelShader_Common.hlsli" + +float4 main(PixelShaderInput input) : SV_TARGET +{ + return GetOutputColor(1.0) * input.color; +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Common.hlsli b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Common.hlsli new file mode 100644 index 0000000..b940c0c --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Common.hlsli @@ -0,0 +1,235 @@ + +Texture2D texture0 : register(t0); +Texture2D texture1 : register(t1); +Texture2D texture2 : register(t2); +SamplerState sampler0 : register(s0); + +struct PixelShaderInput +{ + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; +}; + +// These should mirror the definitions in SDL_render_d3d11.c +static const float TONEMAP_NONE = 0; +static const float TONEMAP_LINEAR = 1; +static const float TONEMAP_CHROME = 2; + +static const float TEXTURETYPE_NONE = 0; +static const float TEXTURETYPE_RGB = 1; +static const float TEXTURETYPE_NV12 = 2; +static const float TEXTURETYPE_NV21 = 3; +static const float TEXTURETYPE_YUV = 4; + +static const float INPUTTYPE_UNSPECIFIED = 0; +static const float INPUTTYPE_SRGB = 1; +static const float INPUTTYPE_SCRGB = 2; +static const float INPUTTYPE_HDR10 = 3; + +cbuffer Constants : register(b0) +{ + float scRGB_output; + float texture_type; + float input_type; + float color_scale; + + float tonemap_method; + float tonemap_factor1; + float tonemap_factor2; + float sdr_white_point; + + float4 Yoffset; + float4 Rcoeff; + float4 Gcoeff; + float4 Bcoeff; +}; + +static const float3x3 mat709to2020 = { + { 0.627404, 0.329283, 0.043313 }, + { 0.069097, 0.919541, 0.011362 }, + { 0.016391, 0.088013, 0.895595 } +}; + +static const float3x3 mat2020to709 = { + { 1.660496, -0.587656, -0.072840 }, + { -0.124547, 1.132895, -0.008348 }, + { -0.018154, -0.100597, 1.118751 } +}; + +float sRGBtoLinear(float v) +{ + if (v <= 0.04045) { + v = (v / 12.92); + } else { + v = pow(abs(v + 0.055) / 1.055, 2.4); + } + return v; +} + +float sRGBfromLinear(float v) +{ + if (v <= 0.0031308) { + v = (v * 12.92); + } else { + v = (pow(abs(v), 1.0 / 2.4) * 1.055 - 0.055); + } + return v; +} + +float3 PQtoLinear(float3 v) +{ + const float c1 = 0.8359375; + const float c2 = 18.8515625; + const float c3 = 18.6875; + const float oo_m1 = 1.0 / 0.1593017578125; + const float oo_m2 = 1.0 / 78.84375; + + float3 num = max(pow(abs(v), oo_m2) - c1, 0.0); + float3 den = c2 - c3 * pow(abs(v), oo_m2); + return (10000.0 * pow(abs(num / den), oo_m1) / sdr_white_point); +} + +float3 ApplyTonemap(float3 v) +{ + if (tonemap_method == TONEMAP_LINEAR) { + v *= tonemap_factor1; + } else if (tonemap_method == TONEMAP_CHROME) { + if (input_type == INPUTTYPE_SCRGB) { + // Convert to BT.2020 colorspace for tone mapping + v = mul(mat709to2020, v); + } + + float vmax = max(v.r, max(v.g, v.b)); + if (vmax > 0.0) { + float scale = (1.0 + tonemap_factor1 * vmax) / (1.0 + tonemap_factor2 * vmax); + v *= scale; + } + + if (input_type == INPUTTYPE_SCRGB) { + // Convert to BT.709 colorspace after tone mapping + v = mul(mat2020to709, v); + } + } + return v; +} + +float4 GetInputColor(PixelShaderInput input) +{ + float4 rgba; + + if (texture_type == TEXTURETYPE_NONE) { + rgba = 1.0; + } else if (texture_type == TEXTURETYPE_RGB) { + rgba = texture0.Sample(sampler0, input.tex); + } else if (texture_type == TEXTURETYPE_NV12) { + float3 yuv; + yuv.x = texture0.Sample(sampler0, input.tex).r; + yuv.yz = texture1.Sample(sampler0, input.tex).rg; + + yuv += Yoffset.xyz; + rgba.r = dot(yuv, Rcoeff.xyz); + rgba.g = dot(yuv, Gcoeff.xyz); + rgba.b = dot(yuv, Bcoeff.xyz); + rgba.a = 1.0; + } else if (texture_type == TEXTURETYPE_NV21) { + float3 yuv; + yuv.x = texture0.Sample(sampler0, input.tex).r; + yuv.yz = texture1.Sample(sampler0, input.tex).gr; + + yuv += Yoffset.xyz; + rgba.r = dot(yuv, Rcoeff.xyz); + rgba.g = dot(yuv, Gcoeff.xyz); + rgba.b = dot(yuv, Bcoeff.xyz); + rgba.a = 1.0; + } else if (texture_type == TEXTURETYPE_YUV) { + float3 yuv; + yuv.x = texture0.Sample(sampler0, input.tex).r; + yuv.y = texture1.Sample(sampler0, input.tex).r; + yuv.z = texture2.Sample(sampler0, input.tex).r; + + yuv += Yoffset.xyz; + rgba.r = dot(yuv, Rcoeff.xyz); + rgba.g = dot(yuv, Gcoeff.xyz); + rgba.b = dot(yuv, Bcoeff.xyz); + rgba.a = 1.0; + } else { + // Error! + rgba.r = 1.0; + rgba.g = 0.0; + rgba.b = 0.0; + rgba.a = 1.0; + } + return rgba; +} + +float4 GetOutputColor(float4 rgba) +{ + float4 output; + + output.rgb = rgba.rgb * color_scale; + output.a = rgba.a; + + return output; +} + +float3 GetOutputColorFromSRGB(float3 rgb) +{ + float3 output; + + if (scRGB_output) { + rgb.r = sRGBtoLinear(rgb.r); + rgb.g = sRGBtoLinear(rgb.g); + rgb.b = sRGBtoLinear(rgb.b); + } + + output.rgb = rgb * color_scale; + + return output; +} + +float3 GetOutputColorFromLinear(float3 rgb) +{ + float3 output; + + output.rgb = rgb * color_scale; + + if (!scRGB_output) { + output.r = sRGBfromLinear(output.r); + output.g = sRGBfromLinear(output.g); + output.b = sRGBfromLinear(output.b); + output.rgb = saturate(output.rgb); + } + + return output; +} + +float4 AdvancedPixelShader(PixelShaderInput input) +{ + float4 rgba = GetInputColor(input); + float4 output; + + if (input_type == INPUTTYPE_HDR10) { + rgba.rgb = PQtoLinear(rgba.rgb); + } + + if (tonemap_method != TONEMAP_NONE) { + rgba.rgb = ApplyTonemap(rgba.rgb); + } + + if (input_type == INPUTTYPE_SRGB) { + output.rgb = GetOutputColorFromSRGB(rgba.rgb); + output.a = rgba.a; + } else if (input_type == INPUTTYPE_SCRGB) { + output.rgb = GetOutputColorFromLinear(rgba.rgb); + output.a = rgba.a; + } else if (input_type == INPUTTYPE_HDR10) { + rgba.rgb = mul(mat2020to709, rgba.rgb); + output.rgb = GetOutputColorFromLinear(rgba.rgb); + output.a = rgba.a; + } else { + output = GetOutputColor(rgba); + } + + return output * input.color; +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.h b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.h new file mode 100644 index 0000000..996cac6 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.h @@ -0,0 +1,332 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer Constants +// { +// +// float scRGB_output; // Offset: 0 Size: 4 [unused] +// float texture_type; // Offset: 4 Size: 4 [unused] +// float input_type; // Offset: 8 Size: 4 [unused] +// float color_scale; // Offset: 12 Size: 4 +// float tonemap_method; // Offset: 16 Size: 4 [unused] +// float tonemap_factor1; // Offset: 20 Size: 4 [unused] +// float tonemap_factor2; // Offset: 24 Size: 4 [unused] +// float sdr_white_point; // Offset: 28 Size: 4 [unused] +// float4 Yoffset; // Offset: 32 Size: 16 [unused] +// float4 Rcoeff; // Offset: 48 Size: 16 [unused] +// float4 Gcoeff; // Offset: 64 Size: 16 [unused] +// float4 Bcoeff; // Offset: 80 Size: 16 [unused] +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// theSampler sampler NA NA s0 1 +// theTexture texture float4 2d t0 1 +// Constants cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// COLOR 0 xyzw 2 NONE float xyzw +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_TARGET 0 xyzw 0 TARGET float xyzw +// +// +// Constant buffer to DX9 shader constant mappings: +// +// Target Reg Buffer Start Reg # of Regs Data Conversion +// ---------- ------- --------- --------- ---------------------- +// c0 cb0 0 1 ( FLT, FLT, FLT, FLT) +// +// +// Sampler/Resource to DX9 shader sampler mappings: +// +// Target Sampler Source Sampler Source Resource +// -------------- --------------- ---------------- +// s0 s0 t0 +// +// +// Level9 shader bytecode: +// + ps_2_0 + dcl t0.xy + dcl t1 + dcl_2d s0 + texld r0, t0, s0 + mul r0.xyz, r0, c0.w + mul r0, r0, t1 + mov oC0, r0 + +// approximately 4 instruction slots used (1 texture, 3 arithmetic) +ps_4_0 +dcl_constantbuffer CB0[1], immediateIndexed +dcl_sampler s0, mode_default +dcl_resource_texture2d (float,float,float,float) t0 +dcl_input_ps linear v1.xy +dcl_input_ps linear v2.xyzw +dcl_output o0.xyzw +dcl_temps 1 +sample r0.xyzw, v1.xyxx, t0.xyzw, s0 +mul r0.xyz, r0.xyzx, cb0[0].wwww +mul o0.xyzw, r0.xyzw, v2.xyzw +ret +// Approximately 4 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 8, 152, + 224, 210, 182, 254, 37, 89, + 68, 213, 13, 174, 95, 42, + 2, 11, 1, 0, 0, 0, + 132, 5, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 220, 0, 0, 0, 168, 1, + 0, 0, 36, 2, 0, 0, + 220, 4, 0, 0, 80, 5, + 0, 0, 65, 111, 110, 57, + 156, 0, 0, 0, 156, 0, + 0, 0, 0, 2, 255, 255, + 104, 0, 0, 0, 52, 0, + 0, 0, 1, 0, 40, 0, + 0, 0, 52, 0, 0, 0, + 52, 0, 1, 0, 36, 0, + 0, 0, 52, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 255, 255, + 31, 0, 0, 2, 0, 0, + 0, 128, 0, 0, 3, 176, + 31, 0, 0, 2, 0, 0, + 0, 128, 1, 0, 15, 176, + 31, 0, 0, 2, 0, 0, + 0, 144, 0, 8, 15, 160, + 66, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 228, 176, + 0, 8, 228, 160, 5, 0, + 0, 3, 0, 0, 7, 128, + 0, 0, 228, 128, 0, 0, + 255, 160, 5, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 1, 0, 228, 176, + 1, 0, 0, 2, 0, 8, + 15, 128, 0, 0, 228, 128, + 255, 255, 0, 0, 83, 72, + 68, 82, 196, 0, 0, 0, + 64, 0, 0, 0, 49, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 90, 0, 0, 3, 0, 96, + 16, 0, 0, 0, 0, 0, + 88, 24, 0, 4, 0, 112, + 16, 0, 0, 0, 0, 0, + 85, 85, 0, 0, 98, 16, + 0, 3, 50, 16, 16, 0, + 1, 0, 0, 0, 98, 16, + 0, 3, 242, 16, 16, 0, + 2, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 0, 0, 0, 0, 104, 0, + 0, 2, 1, 0, 0, 0, + 69, 0, 0, 9, 242, 0, + 16, 0, 0, 0, 0, 0, + 70, 16, 16, 0, 1, 0, + 0, 0, 70, 126, 16, 0, + 0, 0, 0, 0, 0, 96, + 16, 0, 0, 0, 0, 0, + 56, 0, 0, 8, 114, 0, + 16, 0, 0, 0, 0, 0, + 70, 2, 16, 0, 0, 0, + 0, 0, 246, 143, 32, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 56, 0, 0, 7, + 242, 32, 16, 0, 0, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 70, 30, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 116, 0, 0, 0, + 4, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 82, 68, 69, 70, + 176, 2, 0, 0, 1, 0, + 0, 0, 156, 0, 0, 0, + 3, 0, 0, 0, 28, 0, + 0, 0, 0, 4, 255, 255, + 0, 1, 0, 0, 133, 2, + 0, 0, 124, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 135, 0, + 0, 0, 2, 0, 0, 0, + 5, 0, 0, 0, 4, 0, + 0, 0, 255, 255, 255, 255, + 0, 0, 0, 0, 1, 0, + 0, 0, 13, 0, 0, 0, + 146, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, + 0, 0, 116, 104, 101, 83, + 97, 109, 112, 108, 101, 114, + 0, 116, 104, 101, 84, 101, + 120, 116, 117, 114, 101, 0, + 67, 111, 110, 115, 116, 97, + 110, 116, 115, 0, 146, 0, + 0, 0, 12, 0, 0, 0, + 180, 0, 0, 0, 96, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 212, 1, + 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 244, 1, + 0, 0, 4, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 1, 2, + 0, 0, 8, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 12, 2, + 0, 0, 12, 0, 0, 0, + 4, 0, 0, 0, 2, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 24, 2, + 0, 0, 16, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 39, 2, + 0, 0, 20, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 55, 2, + 0, 0, 24, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 71, 2, + 0, 0, 28, 0, 0, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 228, 1, 0, 0, + 0, 0, 0, 0, 87, 2, + 0, 0, 32, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 96, 2, 0, 0, + 0, 0, 0, 0, 112, 2, + 0, 0, 48, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 96, 2, 0, 0, + 0, 0, 0, 0, 119, 2, + 0, 0, 64, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 96, 2, 0, 0, + 0, 0, 0, 0, 126, 2, + 0, 0, 80, 0, 0, 0, + 16, 0, 0, 0, 0, 0, + 0, 0, 96, 2, 0, 0, + 0, 0, 0, 0, 115, 99, + 82, 71, 66, 95, 111, 117, + 116, 112, 117, 116, 0, 171, + 171, 171, 0, 0, 3, 0, + 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 116, 101, 120, 116, 117, 114, + 101, 95, 116, 121, 112, 101, + 0, 105, 110, 112, 117, 116, + 95, 116, 121, 112, 101, 0, + 99, 111, 108, 111, 114, 95, + 115, 99, 97, 108, 101, 0, + 116, 111, 110, 101, 109, 97, + 112, 95, 109, 101, 116, 104, + 111, 100, 0, 116, 111, 110, + 101, 109, 97, 112, 95, 102, + 97, 99, 116, 111, 114, 49, + 0, 116, 111, 110, 101, 109, + 97, 112, 95, 102, 97, 99, + 116, 111, 114, 50, 0, 115, + 100, 114, 95, 119, 104, 105, + 116, 101, 95, 112, 111, 105, + 110, 116, 0, 89, 111, 102, + 102, 115, 101, 116, 0, 171, + 1, 0, 3, 0, 1, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 82, 99, + 111, 101, 102, 102, 0, 71, + 99, 111, 101, 102, 102, 0, + 66, 99, 111, 101, 102, 102, + 0, 77, 105, 99, 114, 111, + 115, 111, 102, 116, 32, 40, + 82, 41, 32, 72, 76, 83, + 76, 32, 83, 104, 97, 100, + 101, 114, 32, 67, 111, 109, + 112, 105, 108, 101, 114, 32, + 49, 48, 46, 49, 0, 171, + 171, 171, 73, 83, 71, 78, + 108, 0, 0, 0, 3, 0, + 0, 0, 8, 0, 0, 0, + 80, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 92, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 3, 3, 0, 0, + 101, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 15, 15, 0, 0, + 83, 86, 95, 80, 79, 83, + 73, 84, 73, 79, 78, 0, + 84, 69, 88, 67, 79, 79, + 82, 68, 0, 67, 79, 76, + 79, 82, 0, 171, 79, 83, + 71, 78, 44, 0, 0, 0, + 1, 0, 0, 0, 8, 0, + 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 83, 86, 95, 84, + 65, 82, 71, 69, 84, 0, + 171, 171 +}; diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl new file mode 100644 index 0000000..f2ecf18 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_PixelShader_Textures.hlsl @@ -0,0 +1,9 @@ +Texture2D theTexture : register(t0); +SamplerState theSampler : register(s0); + +#include "D3D11_PixelShader_Common.hlsli" + +float4 main(PixelShaderInput input) : SV_TARGET +{ + return GetOutputColor(theTexture.Sample(theSampler, input.tex)) * input.color; +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.h b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.h new file mode 100644 index 0000000..97beaa3 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.h @@ -0,0 +1,339 @@ +#if 0 +// +// Generated by Microsoft (R) HLSL Shader Compiler 10.1 +// +// +// Buffer Definitions: +// +// cbuffer VertexShaderConstants +// { +// +// row_major float4x4 model; // Offset: 0 Size: 64 +// row_major float4x4 projectionAndView;// Offset: 64 Size: 64 +// +// } +// +// +// Resource Bindings: +// +// Name Type Format Dim HLSL Bind Count +// ------------------------------ ---------- ------- ----------- -------------- ------ +// VertexShaderConstants cbuffer NA NA cb0 1 +// +// +// +// Input signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// POSITION 0 xyz 0 NONE float xyz +// TEXCOORD 0 xy 1 NONE float xy +// COLOR 0 xyzw 2 NONE float xyzw +// +// +// Output signature: +// +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------- ------ +// SV_POSITION 0 xyzw 0 POS float xyzw +// TEXCOORD 0 xy 1 NONE float xy +// COLOR 0 xyzw 2 NONE float xyzw +// +// +// Constant buffer to DX9 shader constant mappings: +// +// Target Reg Buffer Start Reg # of Regs Data Conversion +// ---------- ------- --------- --------- ---------------------- +// c1 cb0 0 8 ( FLT, FLT, FLT, FLT) +// +// +// Runtime generated constant mappings: +// +// Target Reg Constant Description +// ---------- -------------------------------------------------- +// c0 Vertex Shader position offset +// +// +// Level9 shader bytecode: +// + vs_2_0 + dcl_texcoord v0 + dcl_texcoord1 v1 + dcl_texcoord2 v2 + mul r0, v0.y, c2 + mad r0, v0.x, c1, r0 + mad r0, v0.z, c3, r0 + add r0, r0, c4 + mul r1, r0.y, c6 + mad r1, r0.x, c5, r1 + mad r1, r0.z, c7, r1 + mad r0, r0.w, c8, r1 + mad oPos.xy, r0.w, c0, r0 + mov oPos.zw, r0 + mov oT0.xy, v1 + mov oT1, v2 + +// approximately 12 instruction slots used +vs_4_0 +dcl_constantbuffer CB0[8], immediateIndexed +dcl_input v0.xyz +dcl_input v1.xy +dcl_input v2.xyzw +dcl_output_siv o0.xyzw, position +dcl_output o1.xy +dcl_output o2.xyzw +dcl_temps 2 +mul r0.xyzw, v0.yyyy, cb0[1].xyzw +mad r0.xyzw, v0.xxxx, cb0[0].xyzw, r0.xyzw +mad r0.xyzw, v0.zzzz, cb0[2].xyzw, r0.xyzw +add r0.xyzw, r0.xyzw, cb0[3].xyzw +mul r1.xyzw, r0.yyyy, cb0[5].xyzw +mad r1.xyzw, r0.xxxx, cb0[4].xyzw, r1.xyzw +mad r1.xyzw, r0.zzzz, cb0[6].xyzw, r1.xyzw +mad o0.xyzw, r0.wwww, cb0[7].xyzw, r1.xyzw +mov o1.xy, v1.xyxx +mov o2.xyzw, v2.xyzw +ret +// Approximately 11 instruction slots used +#endif + +const BYTE g_main[] = +{ + 68, 88, 66, 67, 152, 172, + 81, 45, 198, 200, 12, 38, + 143, 4, 178, 228, 158, 175, + 169, 64, 1, 0, 0, 0, + 140, 5, 0, 0, 6, 0, + 0, 0, 56, 0, 0, 0, + 108, 1, 0, 0, 52, 3, + 0, 0, 176, 3, 0, 0, + 168, 4, 0, 0, 24, 5, + 0, 0, 65, 111, 110, 57, + 44, 1, 0, 0, 44, 1, + 0, 0, 0, 2, 254, 255, + 248, 0, 0, 0, 52, 0, + 0, 0, 1, 0, 36, 0, + 0, 0, 48, 0, 0, 0, + 48, 0, 0, 0, 36, 0, + 1, 0, 48, 0, 0, 0, + 0, 0, 8, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 254, 255, + 31, 0, 0, 2, 5, 0, + 0, 128, 0, 0, 15, 144, + 31, 0, 0, 2, 5, 0, + 1, 128, 1, 0, 15, 144, + 31, 0, 0, 2, 5, 0, + 2, 128, 2, 0, 15, 144, + 5, 0, 0, 3, 0, 0, + 15, 128, 0, 0, 85, 144, + 2, 0, 228, 160, 4, 0, + 0, 4, 0, 0, 15, 128, + 0, 0, 0, 144, 1, 0, + 228, 160, 0, 0, 228, 128, + 4, 0, 0, 4, 0, 0, + 15, 128, 0, 0, 170, 144, + 3, 0, 228, 160, 0, 0, + 228, 128, 2, 0, 0, 3, + 0, 0, 15, 128, 0, 0, + 228, 128, 4, 0, 228, 160, + 5, 0, 0, 3, 1, 0, + 15, 128, 0, 0, 85, 128, + 6, 0, 228, 160, 4, 0, + 0, 4, 1, 0, 15, 128, + 0, 0, 0, 128, 5, 0, + 228, 160, 1, 0, 228, 128, + 4, 0, 0, 4, 1, 0, + 15, 128, 0, 0, 170, 128, + 7, 0, 228, 160, 1, 0, + 228, 128, 4, 0, 0, 4, + 0, 0, 15, 128, 0, 0, + 255, 128, 8, 0, 228, 160, + 1, 0, 228, 128, 4, 0, + 0, 4, 0, 0, 3, 192, + 0, 0, 255, 128, 0, 0, + 228, 160, 0, 0, 228, 128, + 1, 0, 0, 2, 0, 0, + 12, 192, 0, 0, 228, 128, + 1, 0, 0, 2, 0, 0, + 3, 224, 1, 0, 228, 144, + 1, 0, 0, 2, 1, 0, + 15, 224, 2, 0, 228, 144, + 255, 255, 0, 0, 83, 72, + 68, 82, 192, 1, 0, 0, + 64, 0, 1, 0, 112, 0, + 0, 0, 89, 0, 0, 4, + 70, 142, 32, 0, 0, 0, + 0, 0, 8, 0, 0, 0, + 95, 0, 0, 3, 114, 16, + 16, 0, 0, 0, 0, 0, + 95, 0, 0, 3, 50, 16, + 16, 0, 1, 0, 0, 0, + 95, 0, 0, 3, 242, 16, + 16, 0, 2, 0, 0, 0, + 103, 0, 0, 4, 242, 32, + 16, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 101, 0, + 0, 3, 50, 32, 16, 0, + 1, 0, 0, 0, 101, 0, + 0, 3, 242, 32, 16, 0, + 2, 0, 0, 0, 104, 0, + 0, 2, 2, 0, 0, 0, + 56, 0, 0, 8, 242, 0, + 16, 0, 0, 0, 0, 0, + 86, 21, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 0, 0, + 0, 0, 6, 16, 16, 0, + 0, 0, 0, 0, 70, 142, + 32, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 0, 0, 0, 0, + 166, 26, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 70, 14, 16, 0, + 0, 0, 0, 0, 0, 0, + 0, 8, 242, 0, 16, 0, + 0, 0, 0, 0, 70, 14, + 16, 0, 0, 0, 0, 0, + 70, 142, 32, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 56, 0, 0, 8, 242, 0, + 16, 0, 1, 0, 0, 0, + 86, 5, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 5, 0, + 0, 0, 50, 0, 0, 10, + 242, 0, 16, 0, 1, 0, + 0, 0, 6, 0, 16, 0, + 0, 0, 0, 0, 70, 142, + 32, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 70, 14, + 16, 0, 1, 0, 0, 0, + 50, 0, 0, 10, 242, 0, + 16, 0, 1, 0, 0, 0, + 166, 10, 16, 0, 0, 0, + 0, 0, 70, 142, 32, 0, + 0, 0, 0, 0, 6, 0, + 0, 0, 70, 14, 16, 0, + 1, 0, 0, 0, 50, 0, + 0, 10, 242, 32, 16, 0, + 0, 0, 0, 0, 246, 15, + 16, 0, 0, 0, 0, 0, + 70, 142, 32, 0, 0, 0, + 0, 0, 7, 0, 0, 0, + 70, 14, 16, 0, 1, 0, + 0, 0, 54, 0, 0, 5, + 50, 32, 16, 0, 1, 0, + 0, 0, 70, 16, 16, 0, + 1, 0, 0, 0, 54, 0, + 0, 5, 242, 32, 16, 0, + 2, 0, 0, 0, 70, 30, + 16, 0, 2, 0, 0, 0, + 62, 0, 0, 1, 83, 84, + 65, 84, 116, 0, 0, 0, + 11, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 82, 68, 69, 70, + 240, 0, 0, 0, 1, 0, + 0, 0, 84, 0, 0, 0, + 1, 0, 0, 0, 28, 0, + 0, 0, 0, 4, 254, 255, + 0, 1, 0, 0, 198, 0, + 0, 0, 60, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 86, 101, + 114, 116, 101, 120, 83, 104, + 97, 100, 101, 114, 67, 111, + 110, 115, 116, 97, 110, 116, + 115, 0, 171, 171, 60, 0, + 0, 0, 2, 0, 0, 0, + 108, 0, 0, 0, 128, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 156, 0, + 0, 0, 0, 0, 0, 0, + 64, 0, 0, 0, 2, 0, + 0, 0, 164, 0, 0, 0, + 0, 0, 0, 0, 180, 0, + 0, 0, 64, 0, 0, 0, + 64, 0, 0, 0, 2, 0, + 0, 0, 164, 0, 0, 0, + 0, 0, 0, 0, 109, 111, + 100, 101, 108, 0, 171, 171, + 2, 0, 3, 0, 4, 0, + 4, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 112, 114, + 111, 106, 101, 99, 116, 105, + 111, 110, 65, 110, 100, 86, + 105, 101, 119, 0, 77, 105, + 99, 114, 111, 115, 111, 102, + 116, 32, 40, 82, 41, 32, + 72, 76, 83, 76, 32, 83, + 104, 97, 100, 101, 114, 32, + 67, 111, 109, 112, 105, 108, + 101, 114, 32, 49, 48, 46, + 49, 0, 171, 171, 73, 83, + 71, 78, 104, 0, 0, 0, + 3, 0, 0, 0, 8, 0, + 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 7, 7, + 0, 0, 89, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 1, 0, 0, 0, 3, 3, + 0, 0, 98, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 2, 0, 0, 0, 15, 15, + 0, 0, 80, 79, 83, 73, + 84, 73, 79, 78, 0, 84, + 69, 88, 67, 79, 79, 82, + 68, 0, 67, 79, 76, 79, + 82, 0, 79, 83, 71, 78, + 108, 0, 0, 0, 3, 0, + 0, 0, 8, 0, 0, 0, + 80, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, + 3, 0, 0, 0, 0, 0, + 0, 0, 15, 0, 0, 0, + 92, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 3, 12, 0, 0, + 101, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 15, 0, 0, 0, + 83, 86, 95, 80, 79, 83, + 73, 84, 73, 79, 78, 0, + 84, 69, 88, 67, 79, 79, + 82, 68, 0, 67, 79, 76, + 79, 82, 0, 171 +}; diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.hlsl b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.hlsl new file mode 100644 index 0000000..63e5172 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/D3D11_VertexShader.hlsl @@ -0,0 +1,38 @@ +#pragma pack_matrix( row_major ) + +cbuffer VertexShaderConstants : register(b0) +{ + matrix model; + matrix projectionAndView; +}; + +struct VertexShaderInput +{ + float3 pos : POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; +}; + +struct VertexShaderOutput +{ + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; +}; + +VertexShaderOutput main(VertexShaderInput input) +{ + VertexShaderOutput output; + float4 pos = float4(input.pos, 1.0f); + + // Transform the vertex position into projected space. + pos = mul(pos, model); + pos = mul(pos, projectionAndView); + output.pos = pos; + + // Pass through texture coordinates and color values without transformation + output.tex = input.tex; + output.color = input.color; + + return output; +} diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/SDL_render_d3d11.c b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_render_d3d11.c new file mode 100644 index 0000000..dc1a722 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_render_d3d11.c @@ -0,0 +1,2767 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_D3D11 + +#define COBJMACROS +#include "../../core/windows/SDL_windows.h" +#include "../../video/windows/SDL_windowswindow.h" +#include "../SDL_sysrender.h" +#include "../SDL_d3dmath.h" +#include "../../video/SDL_pixels_c.h" + +#include +#include +#include + +#include "SDL_shaders_d3d11.h" + +#if defined(_MSC_VER) && !defined(__clang__) +#define SDL_COMPOSE_ERROR(str) __FUNCTION__ ", " str +#else +#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str +#endif + +#define SAFE_RELEASE(X) \ + if ((X)) { \ + IUnknown_Release(SDL_static_cast(IUnknown *, X)); \ + X = NULL; \ + } + +/* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when + !!! FIXME: textures are needed. */ + +// Sampler types +typedef enum +{ + D3D11_SAMPLER_NEAREST_CLAMP, + D3D11_SAMPLER_NEAREST_WRAP, + D3D11_SAMPLER_LINEAR_CLAMP, + D3D11_SAMPLER_LINEAR_WRAP, + D3D11_SAMPLER_COUNT +} D3D11_Sampler; + +// Vertex shader, common values +typedef struct +{ + Float4X4 model; + Float4X4 projectionAndView; +} D3D11_VertexShaderConstants; + +// These should mirror the definitions in D3D11_PixelShader_Common.hlsli +//static const float TONEMAP_NONE = 0; +//static const float TONEMAP_LINEAR = 1; +static const float TONEMAP_CHROME = 2; + +//static const float TEXTURETYPE_NONE = 0; +static const float TEXTURETYPE_RGB = 1; +static const float TEXTURETYPE_NV12 = 2; +static const float TEXTURETYPE_NV21 = 3; +static const float TEXTURETYPE_YUV = 4; + +static const float INPUTTYPE_UNSPECIFIED = 0; +static const float INPUTTYPE_SRGB = 1; +static const float INPUTTYPE_SCRGB = 2; +static const float INPUTTYPE_HDR10 = 3; + +typedef struct +{ + float scRGB_output; + float texture_type; + float input_type; + float color_scale; + + float tonemap_method; + float tonemap_factor1; + float tonemap_factor2; + float sdr_white_point; + + float YCbCr_matrix[16]; +} D3D11_PixelShaderConstants; + +typedef struct +{ + ID3D11Buffer *constants; + D3D11_PixelShaderConstants shader_constants; +} D3D11_PixelShaderState; + +// Per-vertex data +typedef struct +{ + Float2 pos; + Float2 tex; + SDL_FColor color; +} D3D11_VertexPositionColor; + +// Per-texture data +typedef struct +{ + int w, h; + ID3D11Texture2D *mainTexture; + ID3D11ShaderResourceView *mainTextureResourceView; + ID3D11RenderTargetView *mainTextureRenderTargetView; + ID3D11Texture2D *stagingTexture; + int lockedTexturePositionX; + int lockedTexturePositionY; + D3D11_FILTER scaleMode; + D3D11_Shader shader; + const float *YCbCr_matrix; +#ifdef SDL_HAVE_YUV + // YV12 texture support + bool yuv; + ID3D11Texture2D *mainTextureU; + ID3D11ShaderResourceView *mainTextureResourceViewU; + ID3D11Texture2D *mainTextureV; + ID3D11ShaderResourceView *mainTextureResourceViewV; + + // NV12 texture support + bool nv12; + ID3D11ShaderResourceView *mainTextureResourceViewNV; + + Uint8 *pixels; + int pitch; + SDL_Rect locked_rect; +#endif +} D3D11_TextureData; + +// Blend mode data +typedef struct +{ + SDL_BlendMode blendMode; + ID3D11BlendState *blendState; +} D3D11_BlendMode; + +// Private renderer data +typedef struct +{ + SDL_SharedObject *hDXGIMod; + SDL_SharedObject *hD3D11Mod; + IDXGIFactory2 *dxgiFactory; + IDXGIAdapter *dxgiAdapter; + IDXGIDebug *dxgiDebug; + ID3D11Device1 *d3dDevice; + ID3D11DeviceContext1 *d3dContext; + IDXGISwapChain1 *swapChain; + DXGI_SWAP_EFFECT swapEffect; + UINT syncInterval; + UINT presentFlags; + ID3D11RenderTargetView *mainRenderTargetView; + ID3D11RenderTargetView *currentOffscreenRenderTargetView; + ID3D11InputLayout *inputLayout; + ID3D11Buffer *vertexBuffers[8]; + size_t vertexBufferSizes[8]; + ID3D11VertexShader *vertexShader; + ID3D11PixelShader *pixelShaders[NUM_SHADERS]; + int blendModesCount; + D3D11_BlendMode *blendModes; + ID3D11SamplerState *samplers[D3D11_SAMPLER_COUNT]; + D3D_FEATURE_LEVEL featureLevel; + bool pixelSizeChanged; + + // Rasterizers + ID3D11RasterizerState *mainRasterizer; + ID3D11RasterizerState *clippedRasterizer; + + // Vertex buffer constants + D3D11_VertexShaderConstants vertexShaderConstantsData; + ID3D11Buffer *vertexShaderConstants; + + // Cached renderer properties + DXGI_MODE_ROTATION rotation; + ID3D11RenderTargetView *currentRenderTargetView; + ID3D11RasterizerState *currentRasterizerState; + ID3D11BlendState *currentBlendState; + D3D11_Shader currentShader; + D3D11_PixelShaderState currentShaderState[NUM_SHADERS]; + ID3D11ShaderResourceView *currentShaderResource; + ID3D11SamplerState *currentSampler; + bool cliprectDirty; + bool currentCliprectEnabled; + SDL_Rect currentCliprect; + SDL_Rect currentViewport; + int currentViewportRotation; + bool viewportDirty; + Float4X4 identity; + int currentVertexBuffer; +} D3D11_RenderData; + +// Define D3D GUIDs here so we don't have to include uuid.lib. + +#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-const-variable" +#endif + +static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; +static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; +static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } }; +static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } }; +static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } }; +static const GUID SDL_IID_IDXGISwapChain2 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } }; +static const GUID SDL_IID_IDXGIDebug1 = { 0xc5a05f0c, 0x16f2, 0x4adf, { 0x9f, 0x4d, 0xa8, 0xc4, 0xd5, 0x8a, 0xc5, 0x50 } }; +static const GUID SDL_IID_IDXGIInfoQueue = { 0xD67441C7, 0x672A, 0x476f, { 0x9E, 0x82, 0xCD, 0x55, 0xB4, 0x49, 0x49, 0xCE } }; +static const GUID SDL_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8 } }; + +#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA +#pragma GCC diagnostic pop +#endif + +SDL_PixelFormat D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) +{ + switch (dxgiFormat) { + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_ARGB8888; + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return SDL_PIXELFORMAT_ABGR8888; + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return SDL_PIXELFORMAT_XRGB8888; + case DXGI_FORMAT_R10G10B10A2_UNORM: + return SDL_PIXELFORMAT_ABGR2101010; + case DXGI_FORMAT_R16G16B16A16_FLOAT: + return SDL_PIXELFORMAT_RGBA64_FLOAT; + default: + return SDL_PIXELFORMAT_UNKNOWN; + } +} + +static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 output_colorspace) +{ + switch (format) { + case SDL_PIXELFORMAT_RGBA64_FLOAT: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case SDL_PIXELFORMAT_ABGR2101010: + return DXGI_FORMAT_R10G10B10A2_UNORM; + case SDL_PIXELFORMAT_ARGB8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + } + return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; + case SDL_PIXELFORMAT_XRGB8888: + if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + } + return DXGI_FORMAT_B8G8R8X8_UNORM; + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + return DXGI_FORMAT_R8_UNORM; + case SDL_PIXELFORMAT_NV12: + case SDL_PIXELFORMAT_NV21: + return DXGI_FORMAT_NV12; + case SDL_PIXELFORMAT_P010: + return DXGI_FORMAT_P010; + default: + return DXGI_FORMAT_UNKNOWN; + } +} + +static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace) +{ + switch (format) { + case SDL_PIXELFORMAT_RGBA64_FLOAT: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case SDL_PIXELFORMAT_ABGR2101010: + return DXGI_FORMAT_R10G10B10A2_UNORM; + case SDL_PIXELFORMAT_ARGB8888: + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + } + return DXGI_FORMAT_B8G8R8A8_UNORM; + case SDL_PIXELFORMAT_ABGR8888: + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + } + return DXGI_FORMAT_R8G8B8A8_UNORM; + case SDL_PIXELFORMAT_XRGB8888: + if (colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; + } + return DXGI_FORMAT_B8G8R8X8_UNORM; + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + case SDL_PIXELFORMAT_NV12: // For the Y texture + case SDL_PIXELFORMAT_NV21: // For the Y texture + return DXGI_FORMAT_R8_UNORM; + case SDL_PIXELFORMAT_P010: // For the Y texture + return DXGI_FORMAT_R16_UNORM; + default: + return DXGI_FORMAT_UNKNOWN; + } +} + +static void D3D11_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture); + +static void D3D11_ReleaseAll(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + + // Release all textures + for (SDL_Texture *texture = renderer->textures; texture; texture = texture->next) { + D3D11_DestroyTexture(renderer, texture); + } + + // Release/reset everything else + if (data) { + int i; + + // Make sure the swap chain is fully released + if (data->d3dContext) { + ID3D11DeviceContext_ClearState(data->d3dContext); + ID3D11DeviceContext_Flush(data->d3dContext); + } + + SAFE_RELEASE(data->vertexShaderConstants); + SAFE_RELEASE(data->clippedRasterizer); + SAFE_RELEASE(data->mainRasterizer); + for (i = 0; i < SDL_arraysize(data->samplers); ++i) { + SAFE_RELEASE(data->samplers[i]); + } + + if (data->blendModesCount > 0) { + for (i = 0; i < data->blendModesCount; ++i) { + SAFE_RELEASE(data->blendModes[i].blendState); + } + SDL_free(data->blendModes); + data->blendModes = NULL; + data->blendModesCount = 0; + } + for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) { + SAFE_RELEASE(data->pixelShaders[i]); + } + for (i = 0; i < SDL_arraysize(data->currentShaderState); ++i) { + SAFE_RELEASE(data->currentShaderState[i].constants); + } + SAFE_RELEASE(data->vertexShader); + for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) { + SAFE_RELEASE(data->vertexBuffers[i]); + } + SAFE_RELEASE(data->inputLayout); + SAFE_RELEASE(data->mainRenderTargetView); + SAFE_RELEASE(data->swapChain); + + SAFE_RELEASE(data->d3dContext); + SAFE_RELEASE(data->d3dDevice); + SAFE_RELEASE(data->dxgiAdapter); + SAFE_RELEASE(data->dxgiFactory); + + data->swapEffect = (DXGI_SWAP_EFFECT)0; + data->rotation = DXGI_MODE_ROTATION_UNSPECIFIED; + data->currentOffscreenRenderTargetView = NULL; + data->currentRenderTargetView = NULL; + data->currentRasterizerState = NULL; + data->currentBlendState = NULL; + data->currentShader = SHADER_NONE; + SDL_zero(data->currentShaderState); + data->currentShaderResource = NULL; + data->currentSampler = NULL; + + // Check for any leaks if in debug mode + if (data->dxgiDebug) { + DXGI_DEBUG_RLO_FLAGS rloFlags = (DXGI_DEBUG_RLO_FLAGS)(DXGI_DEBUG_RLO_DETAIL | DXGI_DEBUG_RLO_IGNORE_INTERNAL); + IDXGIDebug_ReportLiveObjects(data->dxgiDebug, SDL_DXGI_DEBUG_ALL, rloFlags); + SAFE_RELEASE(data->dxgiDebug); + } + + /* Unload the D3D libraries. This should be done last, in order + * to prevent IUnknown::Release() calls from crashing. + */ + if (data->hD3D11Mod) { + SDL_UnloadObject(data->hD3D11Mod); + data->hD3D11Mod = NULL; + } + if (data->hDXGIMod) { + SDL_UnloadObject(data->hDXGIMod); + data->hDXGIMod = NULL; + } + } +} + +static void D3D11_DestroyRenderer(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + if (data) { + D3D11_ReleaseAll(renderer); + SDL_free(data); + } +} + +static D3D11_BLEND GetBlendFunc(SDL_BlendFactor factor) +{ + switch (factor) { + case SDL_BLENDFACTOR_ZERO: + return D3D11_BLEND_ZERO; + case SDL_BLENDFACTOR_ONE: + return D3D11_BLEND_ONE; + case SDL_BLENDFACTOR_SRC_COLOR: + return D3D11_BLEND_SRC_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: + return D3D11_BLEND_INV_SRC_COLOR; + case SDL_BLENDFACTOR_SRC_ALPHA: + return D3D11_BLEND_SRC_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: + return D3D11_BLEND_INV_SRC_ALPHA; + case SDL_BLENDFACTOR_DST_COLOR: + return D3D11_BLEND_DEST_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: + return D3D11_BLEND_INV_DEST_COLOR; + case SDL_BLENDFACTOR_DST_ALPHA: + return D3D11_BLEND_DEST_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: + return D3D11_BLEND_INV_DEST_ALPHA; + default: + return (D3D11_BLEND)0; + } +} + +static D3D11_BLEND_OP GetBlendEquation(SDL_BlendOperation operation) +{ + switch (operation) { + case SDL_BLENDOPERATION_ADD: + return D3D11_BLEND_OP_ADD; + case SDL_BLENDOPERATION_SUBTRACT: + return D3D11_BLEND_OP_SUBTRACT; + case SDL_BLENDOPERATION_REV_SUBTRACT: + return D3D11_BLEND_OP_REV_SUBTRACT; + case SDL_BLENDOPERATION_MINIMUM: + return D3D11_BLEND_OP_MIN; + case SDL_BLENDOPERATION_MAXIMUM: + return D3D11_BLEND_OP_MAX; + default: + return (D3D11_BLEND_OP)0; + } +} + +static ID3D11BlendState *D3D11_CreateBlendState(SDL_Renderer *renderer, SDL_BlendMode blendMode) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + 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); + ID3D11BlendState *blendState = NULL; + D3D11_BlendMode *blendModes; + HRESULT result = S_OK; + + D3D11_BLEND_DESC blendDesc; + SDL_zero(blendDesc); + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + blendDesc.RenderTarget[0].BlendEnable = TRUE; + blendDesc.RenderTarget[0].SrcBlend = GetBlendFunc(srcColorFactor); + blendDesc.RenderTarget[0].DestBlend = GetBlendFunc(dstColorFactor); + blendDesc.RenderTarget[0].BlendOp = GetBlendEquation(colorOperation); + blendDesc.RenderTarget[0].SrcBlendAlpha = GetBlendFunc(srcAlphaFactor); + blendDesc.RenderTarget[0].DestBlendAlpha = GetBlendFunc(dstAlphaFactor); + blendDesc.RenderTarget[0].BlendOpAlpha = GetBlendEquation(alphaOperation); + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + result = ID3D11Device_CreateBlendState(data->d3dDevice, &blendDesc, &blendState); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBlendState"), result); + return NULL; + } + + blendModes = (D3D11_BlendMode *)SDL_realloc(data->blendModes, (data->blendModesCount + 1) * sizeof(*blendModes)); + if (!blendModes) { + SAFE_RELEASE(blendState); + return NULL; + } + blendModes[data->blendModesCount].blendMode = blendMode; + blendModes[data->blendModesCount].blendState = blendState; + data->blendModes = blendModes; + ++data->blendModesCount; + + return blendState; +} + +// Create resources that depend on the device. +static HRESULT D3D11_CreateDeviceResources(SDL_Renderer *renderer) +{ + typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); + typedef HRESULT(WINAPI * PFN_CREATE_DXGI_FACTORY2)(UINT flags, REFIID riid, void **ppFactory); + PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc = NULL; + PFN_CREATE_DXGI_FACTORY2 CreateDXGIFactory2Func = NULL; + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc; + ID3D11Device *d3dDevice = NULL; + ID3D11DeviceContext *d3dContext = NULL; + IDXGIDevice1 *dxgiDevice = NULL; + HRESULT result = S_OK; + UINT creationFlags = 0; + bool createDebug; + + /* This array defines the set of DirectX hardware feature levels this app will support. + * Note the ordering should be preserved. + * Don't forget to declare your application's minimum required feature level in its + * description. All applications are assumed to support 9.1 unless otherwise stated. + */ + D3D_FEATURE_LEVEL featureLevels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + + D3D11_BUFFER_DESC constantBufferDesc; + D3D11_SAMPLER_DESC samplerDesc; + D3D11_RASTERIZER_DESC rasterDesc; + + // See if we need debug interfaces + createDebug = SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D11_DEBUG, false); + + data->hDXGIMod = SDL_LoadObject("dxgi.dll"); + if (!data->hDXGIMod) { + result = E_FAIL; + goto done; + } + + CreateDXGIFactory2Func = (PFN_CREATE_DXGI_FACTORY2)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory2"); + if (!CreateDXGIFactory2Func) { + CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory"); + if (!CreateDXGIFactoryFunc) { + result = E_FAIL; + goto done; + } + } + + data->hD3D11Mod = SDL_LoadObject("d3d11.dll"); + if (!data->hD3D11Mod) { + result = E_FAIL; + goto done; + } + + D3D11CreateDeviceFunc = (PFN_D3D11_CREATE_DEVICE)SDL_LoadFunction(data->hD3D11Mod, "D3D11CreateDevice"); + if (!D3D11CreateDeviceFunc) { + result = E_FAIL; + goto done; + } + + if (createDebug) { +#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__ + IDXGIInfoQueue *dxgiInfoQueue = NULL; + PFN_CREATE_DXGI_FACTORY2 DXGIGetDebugInterfaceFunc; + + // If the debug hint is set, also create the DXGI factory in debug mode + DXGIGetDebugInterfaceFunc = (PFN_CREATE_DXGI_FACTORY2)SDL_LoadFunction(data->hDXGIMod, "DXGIGetDebugInterface1"); + if (!DXGIGetDebugInterfaceFunc) { + result = E_FAIL; + goto done; + } + + result = DXGIGetDebugInterfaceFunc(0, &SDL_IID_IDXGIDebug1, (void **)&data->dxgiDebug); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("DXGIGetDebugInterface1"), result); + goto done; + } + + result = DXGIGetDebugInterfaceFunc(0, &SDL_IID_IDXGIInfoQueue, (void **)&dxgiInfoQueue); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("DXGIGetDebugInterface1"), result); + goto done; + } + + IDXGIInfoQueue_SetBreakOnSeverity(dxgiInfoQueue, SDL_DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); + IDXGIInfoQueue_SetBreakOnSeverity(dxgiInfoQueue, SDL_DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); + SAFE_RELEASE(dxgiInfoQueue); +#endif // __IDXGIInfoQueue_INTERFACE_DEFINED__ + creationFlags = DXGI_CREATE_FACTORY_DEBUG; + } + + if (CreateDXGIFactory2Func) { + result = CreateDXGIFactory2Func(creationFlags, &SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); + } else { + result = CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory); + } + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("CreateDXGIFactory"), result); + goto done; + } + + // FIXME: Should we use the default adapter? + result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &data->dxgiAdapter); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result); + goto done; + } + + /* This flag adds support for surfaces with a different color channel ordering + * than the API default. It is required for compatibility with Direct2D. + */ + creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; + + // Make sure Direct3D's debugging feature gets used, if the app requests it. + if (createDebug) { + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + } + + // Create a single-threaded device unless the app requests otherwise. + if (!SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, false)) { + creationFlags |= D3D11_CREATE_DEVICE_SINGLETHREADED; + } + + // Create the Direct3D 11 API device object and a corresponding context. + result = D3D11CreateDeviceFunc( + data->dxgiAdapter, + D3D_DRIVER_TYPE_UNKNOWN, + NULL, + creationFlags, // Set set debug and Direct2D compatibility flags. + featureLevels, // List of feature levels this app can support. + SDL_arraysize(featureLevels), + D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps. + &d3dDevice, // Returns the Direct3D device created. + &data->featureLevel, // Returns feature level of device created. + &d3dContext // Returns the device immediate context. + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result); + goto done; + } + + result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_ID3D11Device1, (void **)&data->d3dDevice); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to ID3D11Device1"), result); + goto done; + } + + result = ID3D11DeviceContext_QueryInterface(d3dContext, &SDL_IID_ID3D11DeviceContext1, (void **)&data->d3dContext); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext to ID3D11DeviceContext1"), result); + goto done; + } + + result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_IDXGIDevice1, (void **)&dxgiDevice); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to IDXGIDevice1"), result); + goto done; + } + + /* Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and + * ensures that the application will only render after each VSync, minimizing power consumption. + */ + result = IDXGIDevice1_SetMaximumFrameLatency(dxgiDevice, 1); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIDevice1::SetMaximumFrameLatency"), result); + goto done; + } + + /* Make note of the maximum texture size + * Max texture sizes are documented on MSDN, at: + * http://msdn.microsoft.com/en-us/library/windows/apps/ff476876.aspx + */ + switch (data->featureLevel) { + case D3D_FEATURE_LEVEL_11_1: + case D3D_FEATURE_LEVEL_11_0: + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); + break; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 8192); + break; + + case D3D_FEATURE_LEVEL_9_3: + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 4096); + break; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 2048); + break; + + default: + SDL_SetError("%s, Unexpected feature level: %d", __FUNCTION__, data->featureLevel); + result = E_FAIL; + goto done; + } + + if (!D3D11_CreateVertexShader(data->d3dDevice, &data->vertexShader, &data->inputLayout)) { + goto done; + } + + // Setup space to hold vertex shader constants: + SDL_zero(constantBufferDesc); + constantBufferDesc.ByteWidth = sizeof(D3D11_VertexShaderConstants); + constantBufferDesc.Usage = D3D11_USAGE_DEFAULT; + constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + result = ID3D11Device_CreateBuffer(data->d3dDevice, + &constantBufferDesc, + NULL, + &data->vertexShaderConstants); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex shader constants]"), result); + goto done; + } + + // Create samplers to use when drawing textures: + static struct + { + D3D11_FILTER filter; + D3D11_TEXTURE_ADDRESS_MODE address; + } samplerParams[] = { + { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_CLAMP }, + { D3D11_FILTER_MIN_MAG_MIP_POINT, D3D11_TEXTURE_ADDRESS_WRAP }, + { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_CLAMP }, + { D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_WRAP }, + }; + SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == D3D11_SAMPLER_COUNT); + SDL_zero(samplerDesc); + samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; + samplerDesc.MipLODBias = 0.0f; + samplerDesc.MaxAnisotropy = 1; + samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS; + samplerDesc.MinLOD = 0.0f; + samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; + for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { + samplerDesc.Filter = samplerParams[i].filter; + samplerDesc.AddressU = samplerParams[i].address; + samplerDesc.AddressV = samplerParams[i].address; + result = ID3D11Device_CreateSamplerState(data->d3dDevice, + &samplerDesc, + &data->samplers[i]); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result); + goto done; + } + } + + // Setup Direct3D rasterizer states + SDL_zero(rasterDesc); + rasterDesc.AntialiasedLineEnable = FALSE; + rasterDesc.CullMode = D3D11_CULL_NONE; + rasterDesc.DepthBias = 0; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = TRUE; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.ScissorEnable = FALSE; + rasterDesc.SlopeScaledDepthBias = 0.0f; + result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->mainRasterizer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [main rasterizer]"), result); + goto done; + } + + rasterDesc.ScissorEnable = TRUE; + result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->clippedRasterizer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [clipped rasterizer]"), result); + goto done; + } + + // Create blending states: + if (!D3D11_CreateBlendState(renderer, SDL_BLENDMODE_BLEND)) { + // D3D11_CreateBlendState will set the SDL error, if it fails + goto done; + } + + // Setup render state that doesn't change + ID3D11DeviceContext_IASetInputLayout(data->d3dContext, data->inputLayout); + ID3D11DeviceContext_VSSetShader(data->d3dContext, data->vertexShader, NULL, 0); + ID3D11DeviceContext_VSSetConstantBuffers(data->d3dContext, 0, 1, &data->vertexShaderConstants); + + SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D11_DEVICE_POINTER, data->d3dDevice); + +done: + SAFE_RELEASE(d3dDevice); + SAFE_RELEASE(d3dContext); + SAFE_RELEASE(dxgiDevice); + return result; +} + +static DXGI_MODE_ROTATION D3D11_GetCurrentRotation(void) +{ + // FIXME + return DXGI_MODE_ROTATION_IDENTITY; +} + +static BOOL D3D11_IsDisplayRotated90Degrees(DXGI_MODE_ROTATION rotation) +{ + switch (rotation) { + case DXGI_MODE_ROTATION_ROTATE90: + case DXGI_MODE_ROTATION_ROTATE270: + return TRUE; + default: + return FALSE; + } +} + +static int D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + if (data->currentOffscreenRenderTargetView) { + return DXGI_MODE_ROTATION_IDENTITY; + } else { + return data->rotation; + } +} + +static bool D3D11_GetViewportAlignedD3DRect(SDL_Renderer *renderer, const SDL_Rect *sdlRect, D3D11_RECT *outRect, BOOL includeViewportOffset) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer); + const SDL_Rect *viewport = &data->currentViewport; + + switch (rotation) { + case DXGI_MODE_ROTATION_IDENTITY: + outRect->left = sdlRect->x; + outRect->right = (LONG)sdlRect->x + sdlRect->w; + outRect->top = sdlRect->y; + outRect->bottom = (LONG)sdlRect->y + sdlRect->h; + if (includeViewportOffset) { + outRect->left += viewport->x; + outRect->right += viewport->x; + outRect->top += viewport->y; + outRect->bottom += viewport->y; + } + break; + case DXGI_MODE_ROTATION_ROTATE270: + outRect->left = sdlRect->y; + outRect->right = (LONG)sdlRect->y + sdlRect->h; + outRect->top = viewport->w - sdlRect->x - sdlRect->w; + outRect->bottom = viewport->w - sdlRect->x; + break; + case DXGI_MODE_ROTATION_ROTATE180: + outRect->left = viewport->w - sdlRect->x - sdlRect->w; + outRect->right = viewport->w - sdlRect->x; + outRect->top = viewport->h - sdlRect->y - sdlRect->h; + outRect->bottom = viewport->h - sdlRect->y; + break; + case DXGI_MODE_ROTATION_ROTATE90: + outRect->left = viewport->h - sdlRect->y - sdlRect->h; + outRect->right = viewport->h - sdlRect->y; + outRect->top = sdlRect->x; + outRect->bottom = (LONG)sdlRect->x + sdlRect->h; + break; + default: + return SDL_SetError("The physical display is in an unknown or unsupported rotation"); + } + return true; +} + +static HRESULT D3D11_CreateSwapChain(SDL_Renderer *renderer, int w, int h) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + IUnknown *coreWindow = NULL; + IDXGISwapChain3 *swapChain3 = NULL; + HRESULT result = S_OK; + + // Create a swap chain using the same adapter as the existing Direct3D device. + DXGI_SWAP_CHAIN_DESC1 swapChainDesc; + SDL_zero(swapChainDesc); + swapChainDesc.Width = w; + swapChainDesc.Height = h; + switch (renderer->output_colorspace) { + case SDL_COLORSPACE_SRGB_LINEAR: + swapChainDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + break; + case SDL_COLORSPACE_HDR10: + swapChainDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; + break; + default: + swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format. + break; + } + swapChainDesc.Stereo = FALSE; + swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling. + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency. + if (WIN_IsWindows8OrGreater()) { + swapChainDesc.Scaling = DXGI_SCALING_NONE; + } else { + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + } + if (SDL_GetWindowFlags(renderer->window) & SDL_WINDOW_TRANSPARENT) { + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + } else { + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. + } + swapChainDesc.Flags = 0; + + if (coreWindow) { + result = IDXGIFactory2_CreateSwapChainForCoreWindow(data->dxgiFactory, + (IUnknown *)data->d3dDevice, + coreWindow, + &swapChainDesc, + NULL, // Allow on all displays. + &data->swapChain); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForCoreWindow"), result); + goto done; + } + } else { +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(renderer->window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + if (!hwnd) { + SDL_SetError("Couldn't get window handle"); + result = E_FAIL; + goto done; + } + + result = IDXGIFactory2_CreateSwapChainForHwnd(data->dxgiFactory, + (IUnknown *)data->d3dDevice, + hwnd, + &swapChainDesc, + NULL, + NULL, // Allow on all displays. + &data->swapChain); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForHwnd"), result); + goto done; + } + + IDXGIFactory_MakeWindowAssociation(data->dxgiFactory, hwnd, DXGI_MWA_NO_WINDOW_CHANGES); +#else + SDL_SetError(__FUNCTION__ ", Unable to find something to attach a swap chain to"); + goto done; +#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) / else + } + data->swapEffect = swapChainDesc.SwapEffect; + + if (SUCCEEDED(IDXGISwapChain1_QueryInterface(data->swapChain, &SDL_IID_IDXGISwapChain2, (void **)&swapChain3))) { + UINT colorspace_support = 0; + DXGI_COLOR_SPACE_TYPE colorspace; + switch (renderer->output_colorspace) { + case SDL_COLORSPACE_SRGB_LINEAR: + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + break; + case SDL_COLORSPACE_HDR10: + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + break; + default: + // sRGB + colorspace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + break; + } + if (SUCCEEDED(IDXGISwapChain3_CheckColorSpaceSupport(swapChain3, colorspace, &colorspace_support)) && + (colorspace_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + result = IDXGISwapChain3_SetColorSpace1(swapChain3, colorspace); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain3::SetColorSpace1"), result); + goto done; + } + } else if (colorspace != DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709) { + // Not the default, we're not going to be able to present in this colorspace + SDL_SetError("Unsupported output colorspace"); + result = DXGI_ERROR_UNSUPPORTED; + } + } + + SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D11_SWAPCHAIN_POINTER, data->swapChain); + +done: + SAFE_RELEASE(swapChain3); + SAFE_RELEASE(coreWindow); + return result; +} + +static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL); + SAFE_RELEASE(data->mainRenderTargetView); +} + +// Initialize all resources that change when the window's size changes. +static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + ID3D11Texture2D *backBuffer = NULL; + HRESULT result = S_OK; + int w, h; + + // Release the previous render target view + D3D11_ReleaseMainRenderTargetView(renderer); + + /* The width and height of the swap chain must be based on the display's + * non-rotated size. + */ + SDL_GetWindowSizeInPixels(renderer->window, &w, &h); + data->rotation = D3D11_GetCurrentRotation(); + // SDL_Log("%s: windowSize={%d,%d}, orientation=%d", __FUNCTION__, w, h, (int)data->rotation); + if (D3D11_IsDisplayRotated90Degrees(data->rotation)) { + int tmp = w; + w = h; + h = tmp; + } + + if (data->swapChain) { + // If the swap chain already exists, resize it. + result = IDXGISwapChain_ResizeBuffers(data->swapChain, + 0, + w, h, + DXGI_FORMAT_UNKNOWN, + 0); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result); + goto done; + } + } else { + result = D3D11_CreateSwapChain(renderer, w, h); + if (FAILED(result) || !data->swapChain) { + goto done; + } + } + + // Set the proper rotation for the swap chain. + if (WIN_IsWindows8OrGreater()) { + if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) { + result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain1::SetRotation"), result); + goto done; + } + } + } + + result = IDXGISwapChain_GetBuffer(data->swapChain, + 0, + &SDL_IID_ID3D11Texture2D, + (void **)&backBuffer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::GetBuffer [back-buffer]"), result); + goto done; + } + + // Create a render target view of the swap chain back buffer. + result = ID3D11Device_CreateRenderTargetView(data->d3dDevice, + (ID3D11Resource *)backBuffer, + NULL, + &data->mainRenderTargetView); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateRenderTargetView"), result); + goto done; + } + + /* Set the swap chain target immediately, so that a target is always set + * even before we get to SetDrawState. Without this it's possible to hit + * null references in places like ReadPixels! + */ + ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, + 1, + &data->mainRenderTargetView, + NULL); + + data->viewportDirty = true; + +done: + SAFE_RELEASE(backBuffer); + return result; +} + +static bool D3D11_HandleDeviceLost(SDL_Renderer *renderer) +{ + bool recovered = false; + + D3D11_ReleaseAll(renderer); + + if (SUCCEEDED(D3D11_CreateDeviceResources(renderer)) && + SUCCEEDED(D3D11_CreateWindowSizeDependentResources(renderer))) { + recovered = true; + } else { + SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s", SDL_GetError()); + D3D11_ReleaseAll(renderer); + } + + // Let the application know that the device has been reset or lost + SDL_Event event; + SDL_zero(event); + event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST; + event.render.windowID = SDL_GetWindowID(SDL_GetRenderWindow(renderer)); + SDL_PushEvent(&event); + + return recovered; +} + +// This method is called when the window's size changes. +static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer) +{ + return D3D11_CreateWindowSizeDependentResources(renderer); +} + +static void D3D11_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + + if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { + data->pixelSizeChanged = true; + } +} + +static bool D3D11_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) +{ + 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) || + !GetBlendEquation(colorOperation) || + !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) || + !GetBlendEquation(alphaOperation)) { + return false; + } + return true; +} + +static bool GetTextureProperty(SDL_PropertiesID props, const char *name, ID3D11Texture2D **texture) +{ + IUnknown *unknown = SDL_GetPointerProperty(props, name, NULL); + if (unknown) { + HRESULT result = IUnknown_QueryInterface(unknown, &SDL_IID_ID3D11Texture2D, (void **)texture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(name, result); + } + } + return true; +} + +static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData; + HRESULT result; + DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format, renderer->output_colorspace); + D3D11_TEXTURE2D_DESC textureDesc; + D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; + + if (!rendererData->d3dDevice) { + return SDL_SetError("Device lost and couldn't be recovered"); + } + + if (textureFormat == DXGI_FORMAT_UNKNOWN) { + return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", + __FUNCTION__, texture->format); + } + + textureData = (D3D11_TextureData *)SDL_calloc(1, sizeof(*textureData)); + if (!textureData) { + return false; + } + textureData->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR; + + texture->internal = textureData; + + SDL_zero(textureDesc); + textureDesc.Width = texture->w; + textureDesc.Height = texture->h; + textureDesc.MipLevels = 1; + textureDesc.ArraySize = 1; + textureDesc.Format = textureFormat; + textureDesc.SampleDesc.Count = 1; + textureDesc.SampleDesc.Quality = 0; + textureDesc.MiscFlags = 0; + + // NV12 textures must have even width and height + if (texture->format == SDL_PIXELFORMAT_NV12 || + texture->format == SDL_PIXELFORMAT_NV21 || + texture->format == SDL_PIXELFORMAT_P010) { + textureDesc.Width = (textureDesc.Width + 1) & ~1; + textureDesc.Height = (textureDesc.Height + 1) & ~1; + } + textureData->w = (int)textureDesc.Width; + textureData->h = (int)textureDesc.Height; + if (SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) { + textureData->shader = SHADER_RGB; + } else { + textureData->shader = SHADER_ADVANCED; + } + + if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + textureDesc.Usage = D3D11_USAGE_DYNAMIC; + textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + } else { + textureDesc.Usage = D3D11_USAGE_DEFAULT; + textureDesc.CPUAccessFlags = 0; + } + + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + } else { + textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + } + + if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_POINTER, &textureData->mainTexture)) { + return false; + } + if (!textureData->mainTexture) { + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &textureDesc, + NULL, + &textureData->mainTexture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); + } + } + SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_POINTER, textureData->mainTexture); +#ifdef SDL_HAVE_YUV + if (texture->format == SDL_PIXELFORMAT_YV12 || + texture->format == SDL_PIXELFORMAT_IYUV) { + textureData->yuv = true; + + textureDesc.Width = (textureDesc.Width + 1) / 2; + textureDesc.Height = (textureDesc.Height + 1) / 2; + + if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER, &textureData->mainTextureU)) { + return false; + } + if (!textureData->mainTextureU) { + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &textureDesc, + NULL, + &textureData->mainTextureU); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); + } + } + SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_U_POINTER, textureData->mainTextureU); + + if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER, &textureData->mainTextureV)) { + return false; + } + if (!textureData->mainTextureV) { + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &textureDesc, + NULL, + &textureData->mainTextureV); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); + } + } + SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER, textureData->mainTextureV); + + textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8); + if (!textureData->YCbCr_matrix) { + return SDL_SetError("Unsupported YUV colorspace"); + } + } + if (texture->format == SDL_PIXELFORMAT_NV12 || + texture->format == SDL_PIXELFORMAT_NV21 || + texture->format == SDL_PIXELFORMAT_P010) { + int bits_per_pixel; + + textureData->nv12 = true; + + switch (texture->format) { + case SDL_PIXELFORMAT_P010: + bits_per_pixel = 10; + break; + default: + bits_per_pixel = 8; + break; + } + textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel); + if (!textureData->YCbCr_matrix) { + return SDL_SetError("Unsupported YUV colorspace"); + } + } +#endif // SDL_HAVE_YUV + SDL_zero(resourceViewDesc); + resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format, renderer->output_colorspace); + resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + resourceViewDesc.Texture2D.MostDetailedMip = 0; + resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; + result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, + (ID3D11Resource *)textureData->mainTexture, + &resourceViewDesc, + &textureData->mainTextureResourceView); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); + } +#ifdef SDL_HAVE_YUV + if (textureData->yuv) { + result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, + (ID3D11Resource *)textureData->mainTextureU, + &resourceViewDesc, + &textureData->mainTextureResourceViewU); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); + } + result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, + (ID3D11Resource *)textureData->mainTextureV, + &resourceViewDesc, + &textureData->mainTextureResourceViewV); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); + } + } + + if (textureData->nv12) { + D3D11_SHADER_RESOURCE_VIEW_DESC nvResourceViewDesc = resourceViewDesc; + + if (texture->format == SDL_PIXELFORMAT_NV12 || texture->format == SDL_PIXELFORMAT_NV21) { + nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM; + } else if (texture->format == SDL_PIXELFORMAT_P010) { + nvResourceViewDesc.Format = DXGI_FORMAT_R16G16_UNORM; + } + + result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, + (ID3D11Resource *)textureData->mainTexture, + &nvResourceViewDesc, + &textureData->mainTextureResourceViewNV); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); + } + } +#endif // SDL_HAVE_YUV + + if (texture->access & SDL_TEXTUREACCESS_TARGET) { + D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; + SDL_zero(renderTargetViewDesc); + renderTargetViewDesc.Format = textureDesc.Format; + renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + renderTargetViewDesc.Texture2D.MipSlice = 0; + + result = ID3D11Device_CreateRenderTargetView(rendererData->d3dDevice, + (ID3D11Resource *)textureData->mainTexture, + &renderTargetViewDesc, + &textureData->mainTextureRenderTargetView); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result); + } + } + + return true; +} + +static void D3D11_DestroyTexture(SDL_Renderer *renderer, + SDL_Texture *texture) +{ + D3D11_TextureData *data = (D3D11_TextureData *)texture->internal; + + if (!data) { + return; + } + + SAFE_RELEASE(data->mainTexture); + SAFE_RELEASE(data->mainTextureResourceView); + SAFE_RELEASE(data->mainTextureRenderTargetView); + SAFE_RELEASE(data->stagingTexture); +#ifdef SDL_HAVE_YUV + SAFE_RELEASE(data->mainTextureU); + SAFE_RELEASE(data->mainTextureResourceViewU); + SAFE_RELEASE(data->mainTextureV); + SAFE_RELEASE(data->mainTextureResourceViewV); + SAFE_RELEASE(data->mainTextureResourceViewNV); + SDL_free(data->pixels); +#endif + SDL_free(data); + texture->internal = NULL; +} + +static bool D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch) +{ + ID3D11Texture2D *stagingTexture; + const Uint8 *src; + Uint8 *dst; + int row; + UINT length; + HRESULT result; + D3D11_TEXTURE2D_DESC stagingTextureDesc; + D3D11_MAPPED_SUBRESOURCE textureMemory; + + // Create a 'staging' texture, which will be used to write to a portion of the main texture. + ID3D11Texture2D_GetDesc(texture, &stagingTextureDesc); + stagingTextureDesc.Width = w; + stagingTextureDesc.Height = h; + stagingTextureDesc.BindFlags = 0; + stagingTextureDesc.MiscFlags = 0; + stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + stagingTextureDesc.Usage = D3D11_USAGE_STAGING; + if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 || + stagingTextureDesc.Format == DXGI_FORMAT_P010) { + stagingTextureDesc.Width = (stagingTextureDesc.Width + 1) & ~1; + stagingTextureDesc.Height = (stagingTextureDesc.Height + 1) & ~1; + } + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &stagingTextureDesc, + NULL, + &stagingTexture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); + } + + // Get a write-only pointer to data in the staging texture: + result = ID3D11DeviceContext_Map(rendererData->d3dContext, + (ID3D11Resource *)stagingTexture, + 0, + D3D11_MAP_WRITE, + 0, + &textureMemory); + if (FAILED(result)) { + SAFE_RELEASE(stagingTexture); + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); + } + + src = (const Uint8 *)pixels; + dst = (Uint8 *)textureMemory.pData; + length = w * bpp; + if (length == (UINT)pitch && length == textureMemory.RowPitch) { + SDL_memcpy(dst, src, (size_t)length * h); + } else { + if (length > (UINT)pitch) { + length = pitch; + } + if (length > textureMemory.RowPitch) { + length = textureMemory.RowPitch; + } + for (row = 0; row < h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += textureMemory.RowPitch; + } + } + + if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 || + stagingTextureDesc.Format == DXGI_FORMAT_P010) { + // Copy the UV plane as well + h = (h + 1) / 2; + if (stagingTextureDesc.Format == DXGI_FORMAT_P010) { + length = (length + 3) & ~3; + pitch = (pitch + 3) & ~3; + } else { + length = (length + 1) & ~1; + pitch = (pitch + 1) & ~1; + } + dst = (Uint8 *)textureMemory.pData + stagingTextureDesc.Height * textureMemory.RowPitch; + for (row = 0; row < h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += textureMemory.RowPitch; + } + } + + // Commit the pixel buffer's changes back to the staging texture: + ID3D11DeviceContext_Unmap(rendererData->d3dContext, + (ID3D11Resource *)stagingTexture, + 0); + + // Copy the staging texture's contents back to the texture: + ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext, + (ID3D11Resource *)texture, + 0, + x, + y, + 0, + (ID3D11Resource *)stagingTexture, + 0, + NULL); + + SAFE_RELEASE(stagingTexture); + + return true; +} + +#ifdef SDL_HAVE_YUV +static bool D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch); + +static bool D3D11_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch); +#endif + +static bool D3D11_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, const void *srcPixels, + int srcPitch) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + + if (!textureData) { + return SDL_SetError("Texture is not currently available"); + } + +#ifdef SDL_HAVE_YUV + if (textureData->nv12) { + const Uint8 *Yplane = (const Uint8 *)srcPixels; + const Uint8 *UVplane = Yplane + rect->h * srcPitch; + + return D3D11_UpdateTextureNV(renderer, texture, rect, Yplane, srcPitch, UVplane, srcPitch); + + } else if (textureData->yuv) { + int Ypitch = srcPitch; + int UVpitch = ((Ypitch + 1) / 2); + const Uint8 *Yplane = (const Uint8 *)srcPixels; + const Uint8 *Uplane = Yplane + rect->h * Ypitch; + const Uint8 *Vplane = Uplane + ((rect->h + 1) / 2) * UVpitch; + + if (texture->format == SDL_PIXELFORMAT_YV12) { + return D3D11_UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Vplane, UVpitch, Uplane, UVpitch); + } else { + return D3D11_UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, UVpitch, Vplane, UVpitch); + } + } +#endif + + if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch)) { + return false; + } + return true; +} + +#ifdef SDL_HAVE_YUV +static bool D3D11_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *Uplane, int Upitch, + const Uint8 *Vplane, int Vpitch) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + + if (!textureData) { + return SDL_SetError("Texture is not currently available"); + } + + if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch)) { + return false; + } + if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) { + return false; + } + if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) { + return false; + } + return true; +} + +static bool D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, + const Uint8 *Yplane, int Ypitch, + const Uint8 *UVplane, int UVpitch) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + ID3D11Texture2D *stagingTexture; + const Uint8 *src; + Uint8 *dst; + int w, h, row; + UINT length; + HRESULT result; + D3D11_TEXTURE2D_DESC stagingTextureDesc; + D3D11_MAPPED_SUBRESOURCE textureMemory; + + if (!textureData) { + return SDL_SetError("Texture is not currently available"); + } + + w = rect->w; + h = rect->h; + + // Create a 'staging' texture, which will be used to write to a portion of the main texture. + ID3D11Texture2D_GetDesc(textureData->mainTexture, &stagingTextureDesc); + stagingTextureDesc.Width = w; + stagingTextureDesc.Height = h; + stagingTextureDesc.BindFlags = 0; + stagingTextureDesc.MiscFlags = 0; + stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + stagingTextureDesc.Usage = D3D11_USAGE_STAGING; + if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 || + stagingTextureDesc.Format == DXGI_FORMAT_P010) { + stagingTextureDesc.Width = (stagingTextureDesc.Width + 1) & ~1; + stagingTextureDesc.Height = (stagingTextureDesc.Height + 1) & ~1; + } + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &stagingTextureDesc, + NULL, + &stagingTexture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); + } + + // Get a write-only pointer to data in the staging texture: + result = ID3D11DeviceContext_Map(rendererData->d3dContext, + (ID3D11Resource *)stagingTexture, + 0, + D3D11_MAP_WRITE, + 0, + &textureMemory); + if (FAILED(result)) { + SAFE_RELEASE(stagingTexture); + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); + } + + src = Yplane; + dst = (Uint8 *)textureMemory.pData; + length = w; + if (length == (UINT)Ypitch && length == textureMemory.RowPitch) { + SDL_memcpy(dst, src, (size_t)length * h); + } else { + if (length > (UINT)Ypitch) { + length = Ypitch; + } + if (length > textureMemory.RowPitch) { + length = textureMemory.RowPitch; + } + for (row = 0; row < h; ++row) { + SDL_memcpy(dst, src, length); + src += Ypitch; + dst += textureMemory.RowPitch; + } + } + + src = UVplane; + length = w; + h = (h + 1) / 2; + if (stagingTextureDesc.Format == DXGI_FORMAT_P010) { + length = (length + 3) & ~3; + UVpitch = (UVpitch + 3) & ~3; + } else { + length = (length + 1) & ~1; + UVpitch = (UVpitch + 1) & ~1; + } + dst = (Uint8 *)textureMemory.pData + stagingTextureDesc.Height * textureMemory.RowPitch; + for (row = 0; row < h; ++row) { + SDL_memcpy(dst, src, length); + src += UVpitch; + dst += textureMemory.RowPitch; + } + + // Commit the pixel buffer's changes back to the staging texture: + ID3D11DeviceContext_Unmap(rendererData->d3dContext, + (ID3D11Resource *)stagingTexture, + 0); + + // Copy the staging texture's contents back to the texture: + ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext, + (ID3D11Resource *)textureData->mainTexture, + 0, + rect->x, + rect->y, + 0, + (ID3D11Resource *)stagingTexture, + 0, + NULL); + + SAFE_RELEASE(stagingTexture); + + return true; +} +#endif + +static bool D3D11_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, + const SDL_Rect *rect, void **pixels, int *pitch) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + HRESULT result = S_OK; + D3D11_TEXTURE2D_DESC stagingTextureDesc; + D3D11_MAPPED_SUBRESOURCE textureMemory; + + if (!textureData) { + return SDL_SetError("Texture is not currently available"); + } +#ifdef SDL_HAVE_YUV + if (textureData->yuv || textureData->nv12) { + // It's more efficient to upload directly... + if (!textureData->pixels) { + textureData->pitch = texture->w; + textureData->pixels = (Uint8 *)SDL_malloc((texture->h * textureData->pitch * 3) / 2); + if (!textureData->pixels) { + return false; + } + } + textureData->locked_rect = *rect; + *pixels = + (void *)(textureData->pixels + rect->y * textureData->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = textureData->pitch; + return true; + } +#endif + if (textureData->stagingTexture) { + return SDL_SetError("texture is already locked"); + } + + /* Create a 'staging' texture, which will be used to write to a portion + * of the main texture. This is necessary, as Direct3D 11.1 does not + * have the ability to write a CPU-bound pixel buffer to a rectangular + * subrect of a texture. Direct3D 11.1 can, however, write a pixel + * buffer to an entire texture, hence the use of a staging texture. + */ + ID3D11Texture2D_GetDesc(textureData->mainTexture, &stagingTextureDesc); + stagingTextureDesc.Width = rect->w; + stagingTextureDesc.Height = rect->h; + stagingTextureDesc.BindFlags = 0; + stagingTextureDesc.MiscFlags = 0; + stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + stagingTextureDesc.Usage = D3D11_USAGE_STAGING; + result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, + &stagingTextureDesc, + NULL, + &textureData->stagingTexture); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); + } + + // Get a write-only pointer to data in the staging texture: + result = ID3D11DeviceContext_Map(rendererData->d3dContext, + (ID3D11Resource *)textureData->stagingTexture, + 0, + D3D11_MAP_WRITE, + 0, + &textureMemory); + if (FAILED(result)) { + SAFE_RELEASE(textureData->stagingTexture); + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); + } + + /* Make note of where the staging texture will be written to + * (on a call to SDL_UnlockTexture): + */ + textureData->lockedTexturePositionX = rect->x; + textureData->lockedTexturePositionY = rect->y; + + /* Make sure the caller has information on the texture's pixel buffer, + * then return: + */ + *pixels = textureMemory.pData; + *pitch = textureMemory.RowPitch; + return true; +} + +static void D3D11_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + + if (!textureData) { + return; + } +#ifdef SDL_HAVE_YUV + if (textureData->yuv || textureData->nv12) { + const SDL_Rect *rect = &textureData->locked_rect; + void *pixels = + (void *)(textureData->pixels + rect->y * textureData->pitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + D3D11_UpdateTexture(renderer, texture, rect, pixels, textureData->pitch); + return; + } +#endif + // Commit the pixel buffer's changes back to the staging texture: + ID3D11DeviceContext_Unmap(rendererData->d3dContext, + (ID3D11Resource *)textureData->stagingTexture, + 0); + + // Copy the staging texture's contents back to the main texture: + ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext, + (ID3D11Resource *)textureData->mainTexture, + 0, + textureData->lockedTexturePositionX, + textureData->lockedTexturePositionY, + 0, + (ID3D11Resource *)textureData->stagingTexture, + 0, + NULL); + + SAFE_RELEASE(textureData->stagingTexture); +} + +static void D3D11_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) +{ + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + + if (!textureData) { + return; + } + + textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR; +} + +static bool D3D11_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = NULL; + + if (!texture) { + rendererData->currentOffscreenRenderTargetView = NULL; + return true; + } + + textureData = (D3D11_TextureData *)texture->internal; + + if (!textureData->mainTextureRenderTargetView) { + return SDL_SetError("specified texture is not a render target"); + } + + rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView; + + return true; +} + +static bool D3D11_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) +{ + return true; // nothing to do in this backend. +} + +static bool D3D11_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) +{ + D3D11_VertexPositionColor *verts = (D3D11_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(D3D11_VertexPositionColor), 0, &cmd->data.draw.first); + int i; + SDL_FColor color = cmd->data.draw.color; + bool convert_color = SDL_RenderingLinearSpace(renderer); + + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + + if (convert_color) { + SDL_ConvertToLinear(&color); + } + + for (i = 0; i < count; i++) { + verts->pos.x = points[i].x + 0.5f; + verts->pos.y = points[i].y + 0.5f; + verts->tex.x = 0.0f; + verts->tex.y = 0.0f; + verts->color = color; + verts++; + } + + return true; +} + +static bool D3D11_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y) +{ + int i; + int count = indices ? num_indices : num_vertices; + D3D11_VertexPositionColor *verts = (D3D11_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(D3D11_VertexPositionColor), 0, &cmd->data.draw.first); + bool convert_color = SDL_RenderingLinearSpace(renderer); + D3D11_TextureData *textureData = texture ? (D3D11_TextureData *)texture->internal : NULL; + float u_scale = textureData ? (float)texture->w / textureData->w : 0.0f; + float v_scale = textureData ? (float)texture->h / textureData->h : 0.0f; + + if (!verts) { + return false; + } + + cmd->data.draw.count = count; + size_indices = indices ? size_indices : 0; + + for (i = 0; i < count; i++) { + int j; + float *xy_; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char *)xy + j * xy_stride); + + verts->pos.x = xy_[0] * scale_x; + verts->pos.y = xy_[1] * scale_y; + verts->color = *(SDL_FColor *)((char *)color + j * color_stride); + if (convert_color) { + SDL_ConvertToLinear(&verts->color); + } + + if (texture) { + float *uv_ = (float *)((char *)uv + j * uv_stride); + verts->tex.x = uv_[0] * u_scale; + verts->tex.y = uv_[1] * v_scale; + } else { + verts->tex.x = 0.0f; + verts->tex.y = 0.0f; + } + + verts += 1; + } + return true; +} + +static bool D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, + const void *vertexData, size_t dataSizeInBytes) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + HRESULT result = S_OK; + const int vbidx = rendererData->currentVertexBuffer; + const UINT stride = sizeof(D3D11_VertexPositionColor); + const UINT offset = 0; + + if (dataSizeInBytes == 0) { + return true; // nothing to do. + } + + if (rendererData->vertexBuffers[vbidx] && rendererData->vertexBufferSizes[vbidx] >= dataSizeInBytes) { + D3D11_MAPPED_SUBRESOURCE mappedResource; + result = ID3D11DeviceContext_Map(rendererData->d3dContext, + (ID3D11Resource *)rendererData->vertexBuffers[vbidx], + 0, + D3D11_MAP_WRITE_DISCARD, + 0, + &mappedResource); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result); + } + SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes); + ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffers[vbidx], 0); + } else { + D3D11_BUFFER_DESC vertexBufferDesc; + D3D11_SUBRESOURCE_DATA vertexBufferData; + + SAFE_RELEASE(rendererData->vertexBuffers[vbidx]); + + SDL_zero(vertexBufferDesc); + vertexBufferDesc.ByteWidth = (UINT)dataSizeInBytes; + vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + SDL_zero(vertexBufferData); + vertexBufferData.pSysMem = vertexData; + vertexBufferData.SysMemPitch = 0; + vertexBufferData.SysMemSlicePitch = 0; + + result = ID3D11Device_CreateBuffer(rendererData->d3dDevice, + &vertexBufferDesc, + &vertexBufferData, + &rendererData->vertexBuffers[vbidx]); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result); + } + + rendererData->vertexBufferSizes[vbidx] = dataSizeInBytes; + } + + ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext, + 0, + 1, + &rendererData->vertexBuffers[vbidx], + &stride, + &offset); + + rendererData->currentVertexBuffer++; + if (rendererData->currentVertexBuffer >= SDL_arraysize(rendererData->vertexBuffers)) { + rendererData->currentVertexBuffer = 0; + } + + return true; +} + +static bool D3D11_UpdateViewport(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + const SDL_Rect *viewport = &data->currentViewport; + Float4X4 projection; + Float4X4 view; + SDL_FRect orientationAlignedViewport; + BOOL swapDimensions; + D3D11_VIEWPORT d3dviewport; + const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer); + + if (viewport->w == 0 || viewport->h == 0) { + /* If the viewport is empty, assume that it is because + * SDL_CreateRenderer is calling it, and will call it again later + * with a non-empty viewport. + */ + // SDL_Log("%s, no viewport was set!", __FUNCTION__); + return false; + } + + /* Make sure the SDL viewport gets rotated to that of the physical display's rotation. + * Keep in mind here that the Y-axis will be been inverted (from Direct3D's + * default coordinate system) so rotations will be done in the opposite + * direction of the DXGI_MODE_ROTATION enumeration. + */ + switch (rotation) { + case DXGI_MODE_ROTATION_IDENTITY: + projection = MatrixIdentity(); + break; + case DXGI_MODE_ROTATION_ROTATE270: + projection = MatrixRotationZ(SDL_PI_F * 0.5f); + break; + case DXGI_MODE_ROTATION_ROTATE180: + projection = MatrixRotationZ(SDL_PI_F); + break; + case DXGI_MODE_ROTATION_ROTATE90: + projection = MatrixRotationZ(-SDL_PI_F * 0.5f); + break; + default: + return SDL_SetError("An unknown DisplayOrientation is being used"); + } + + // Update the view matrix + SDL_zero(view); + view.m[0][0] = 2.0f / viewport->w; + view.m[1][1] = -2.0f / viewport->h; + view.m[2][2] = 1.0f; + view.m[3][0] = -1.0f; + view.m[3][1] = 1.0f; + view.m[3][3] = 1.0f; + + /* Combine the projection + view matrix together now, as both only get + * set here (as of this writing, on Dec 26, 2013). When done, store it + * for eventual transfer to the GPU. + */ + data->vertexShaderConstantsData.projectionAndView = MatrixMultiply( + view, + projection); + + /* Update the Direct3D viewport, which seems to be aligned to the + * swap buffer's coordinate space, which is always in either + * a landscape mode, for all Windows 8/RT devices, or a portrait mode, + * for Windows Phone devices. + */ + swapDimensions = D3D11_IsDisplayRotated90Degrees(rotation); + if (swapDimensions) { + orientationAlignedViewport.x = (float)viewport->y; + orientationAlignedViewport.y = (float)viewport->x; + orientationAlignedViewport.w = (float)viewport->h; + orientationAlignedViewport.h = (float)viewport->w; + } else { + orientationAlignedViewport.x = (float)viewport->x; + orientationAlignedViewport.y = (float)viewport->y; + orientationAlignedViewport.w = (float)viewport->w; + orientationAlignedViewport.h = (float)viewport->h; + } + + d3dviewport.TopLeftX = orientationAlignedViewport.x; + d3dviewport.TopLeftY = orientationAlignedViewport.y; + d3dviewport.Width = orientationAlignedViewport.w; + d3dviewport.Height = orientationAlignedViewport.h; + d3dviewport.MinDepth = 0.0f; + d3dviewport.MaxDepth = 1.0f; + // SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); + ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &d3dviewport); + + data->viewportDirty = false; + + return true; +} + +static ID3D11RenderTargetView *D3D11_GetCurrentRenderTargetView(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + if (data->currentOffscreenRenderTargetView) { + return data->currentOffscreenRenderTargetView; + } else { + return data->mainRenderTargetView; + } +} + +static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Texture *texture, D3D11_PixelShaderConstants *constants) +{ + float output_headroom; + + SDL_zerop(constants); + + constants->scRGB_output = (float)SDL_RenderingLinearSpace(renderer); + constants->color_scale = cmd->data.draw.color_scale; + + if (texture) { + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + + switch (texture->format) { + case SDL_PIXELFORMAT_YV12: + case SDL_PIXELFORMAT_IYUV: + constants->texture_type = TEXTURETYPE_YUV; + constants->input_type = INPUTTYPE_SRGB; + break; + case SDL_PIXELFORMAT_NV12: + constants->texture_type = TEXTURETYPE_NV12; + constants->input_type = INPUTTYPE_SRGB; + break; + case SDL_PIXELFORMAT_NV21: + constants->texture_type = TEXTURETYPE_NV21; + constants->input_type = INPUTTYPE_SRGB; + break; + case SDL_PIXELFORMAT_P010: + constants->texture_type = TEXTURETYPE_NV12; + constants->input_type = INPUTTYPE_HDR10; + break; + default: + constants->texture_type = TEXTURETYPE_RGB; + if (texture->colorspace == SDL_COLORSPACE_SRGB_LINEAR) { + constants->input_type = INPUTTYPE_SCRGB; + } else if (texture->colorspace == SDL_COLORSPACE_HDR10) { + constants->input_type = INPUTTYPE_HDR10; + } else { + // The sampler will convert from sRGB to linear on load if working in linear colorspace + constants->input_type = INPUTTYPE_UNSPECIFIED; + } + break; + } + + constants->sdr_white_point = texture->SDR_white_point; + + if (renderer->target) { + output_headroom = renderer->target->HDR_headroom; + } else { + output_headroom = renderer->HDR_headroom; + } + + if (texture->HDR_headroom > output_headroom) { + constants->tonemap_method = TONEMAP_CHROME; + constants->tonemap_factor1 = (output_headroom / (texture->HDR_headroom * texture->HDR_headroom)); + constants->tonemap_factor2 = (1.0f / output_headroom); + } + + if (textureData->YCbCr_matrix) { + SDL_memcpy(constants->YCbCr_matrix, textureData->YCbCr_matrix, sizeof(constants->YCbCr_matrix)); + } + } +} + +static bool D3D11_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, + D3D11_Shader shader, const D3D11_PixelShaderConstants *shader_constants, + const int numShaderResources, ID3D11ShaderResourceView **shaderResources, + ID3D11SamplerState *sampler, const Float4X4 *matrix) + +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity; + ID3D11RasterizerState *rasterizerState; + ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer); + ID3D11ShaderResourceView *shaderResource; + const SDL_BlendMode blendMode = cmd->data.draw.blend; + ID3D11BlendState *blendState = NULL; + bool updateSubresource = false; + D3D11_PixelShaderState *shader_state = &rendererData->currentShaderState[shader]; + D3D11_PixelShaderConstants solid_constants; + + if (numShaderResources > 0) { + shaderResource = shaderResources[0]; + } else { + shaderResource = NULL; + } + + // Make sure the render target isn't bound to a shader + if (shaderResource != rendererData->currentShaderResource) { + ID3D11ShaderResourceView *pNullResource = NULL; + ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, 1, &pNullResource); + rendererData->currentShaderResource = NULL; + } + + if (renderTargetView != rendererData->currentRenderTargetView) { + ID3D11DeviceContext_OMSetRenderTargets(rendererData->d3dContext, + 1, + &renderTargetView, + NULL); + rendererData->currentRenderTargetView = renderTargetView; + } + + if (rendererData->viewportDirty) { + if (D3D11_UpdateViewport(renderer)) { + // vertexShaderConstantsData.projectionAndView has changed + updateSubresource = true; + } + } + + if (rendererData->cliprectDirty) { + if (!rendererData->currentCliprectEnabled) { + ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 0, NULL); + } else { + D3D11_RECT scissorRect; + if (!D3D11_GetViewportAlignedD3DRect(renderer, &rendererData->currentCliprect, &scissorRect, TRUE)) { + // D3D11_GetViewportAlignedD3DRect will have set the SDL error + return false; + } + ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 1, &scissorRect); + } + rendererData->cliprectDirty = false; + } + + if (!rendererData->currentCliprectEnabled) { + rasterizerState = rendererData->mainRasterizer; + } else { + rasterizerState = rendererData->clippedRasterizer; + } + if (rasterizerState != rendererData->currentRasterizerState) { + ID3D11DeviceContext_RSSetState(rendererData->d3dContext, rasterizerState); + rendererData->currentRasterizerState = rasterizerState; + } + + if (blendMode != SDL_BLENDMODE_NONE) { + int i; + for (i = 0; i < rendererData->blendModesCount; ++i) { + if (blendMode == rendererData->blendModes[i].blendMode) { + blendState = rendererData->blendModes[i].blendState; + break; + } + } + if (!blendState) { + blendState = D3D11_CreateBlendState(renderer, blendMode); + if (!blendState) { + return false; + } + } + } + if (blendState != rendererData->currentBlendState) { + ID3D11DeviceContext_OMSetBlendState(rendererData->d3dContext, blendState, 0, 0xFFFFFFFF); + rendererData->currentBlendState = blendState; + } + + if (!shader_constants) { + D3D11_SetupShaderConstants(renderer, cmd, NULL, &solid_constants); + shader_constants = &solid_constants; + } + + if (!shader_state->constants || + SDL_memcmp(shader_constants, &shader_state->shader_constants, sizeof(*shader_constants)) != 0) { + SAFE_RELEASE(shader_state->constants); + + D3D11_BUFFER_DESC desc; + SDL_zero(desc); + desc.Usage = D3D11_USAGE_DEFAULT; + desc.ByteWidth = sizeof(*shader_constants); + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + + D3D11_SUBRESOURCE_DATA data; + SDL_zero(data); + data.pSysMem = shader_constants; + + HRESULT result = ID3D11Device_CreateBuffer(rendererData->d3dDevice, &desc, &data, &shader_state->constants); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateBuffer [create shader constants]"), result); + return false; + } + SDL_memcpy(&shader_state->shader_constants, shader_constants, sizeof(*shader_constants)); + + // Force the shader parameters to be re-set + rendererData->currentShader = SHADER_NONE; + } + if (shader != rendererData->currentShader) { + if (!rendererData->pixelShaders[shader]) { + if (!D3D11_CreatePixelShader(rendererData->d3dDevice, shader, &rendererData->pixelShaders[shader])) { + return false; + } + } + ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, rendererData->pixelShaders[shader], NULL, 0); + if (shader_state->constants) { + ID3D11DeviceContext_PSSetConstantBuffers(rendererData->d3dContext, 0, 1, &shader_state->constants); + } + rendererData->currentShader = shader; + } + if (shaderResource != rendererData->currentShaderResource) { + ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, numShaderResources, shaderResources); + rendererData->currentShaderResource = shaderResource; + } + if (sampler != rendererData->currentSampler) { + ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler); + rendererData->currentSampler = sampler; + } + + if (updateSubresource == true || SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)) != 0) { + SDL_copyp(&rendererData->vertexShaderConstantsData.model, newmatrix); + ID3D11DeviceContext_UpdateSubresource(rendererData->d3dContext, + (ID3D11Resource *)rendererData->vertexShaderConstants, + 0, + NULL, + &rendererData->vertexShaderConstantsData, + 0, + 0); + } + + return true; +} + +static bool D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix) +{ + SDL_Texture *texture = cmd->data.draw.texture; + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + D3D11_TextureData *textureData = (D3D11_TextureData *)texture->internal; + ID3D11SamplerState *textureSampler; + D3D11_PixelShaderConstants constants; + + if (!textureData) { + return SDL_SetError("Texture is not currently available"); + } + + D3D11_SetupShaderConstants(renderer, cmd, texture, &constants); + + switch (textureData->scaleMode) { + case D3D11_FILTER_MIN_MAG_MIP_POINT: + switch (cmd->data.draw.texture_address_mode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + textureSampler = rendererData->samplers[D3D11_SAMPLER_NEAREST_CLAMP]; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + textureSampler = rendererData->samplers[D3D11_SAMPLER_NEAREST_WRAP]; + break; + default: + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); + } + break; + case D3D11_FILTER_MIN_MAG_MIP_LINEAR: + switch (cmd->data.draw.texture_address_mode) { + case SDL_TEXTURE_ADDRESS_CLAMP: + textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_CLAMP]; + break; + case SDL_TEXTURE_ADDRESS_WRAP: + textureSampler = rendererData->samplers[D3D11_SAMPLER_LINEAR_WRAP]; + break; + default: + return SDL_SetError("Unknown texture address mode: %d", cmd->data.draw.texture_address_mode); + } + break; + default: + return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode); + } +#ifdef SDL_HAVE_YUV + if (textureData->yuv) { + ID3D11ShaderResourceView *shaderResources[3]; + + shaderResources[0] = textureData->mainTextureResourceView; + shaderResources[1] = textureData->mainTextureResourceViewU; + shaderResources[2] = textureData->mainTextureResourceViewV; + + return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, + SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix); + + } else if (textureData->nv12) { + ID3D11ShaderResourceView *shaderResources[2]; + + shaderResources[0] = textureData->mainTextureResourceView; + shaderResources[1] = textureData->mainTextureResourceViewNV; + + return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, + SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix); + } +#endif // SDL_HAVE_YUV + return D3D11_SetDrawState(renderer, cmd, textureData->shader, &constants, + 1, &textureData->mainTextureResourceView, textureSampler, matrix); +} + +static void D3D11_DrawPrimitives(SDL_Renderer *renderer, D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, const size_t vertexStart, const size_t vertexCount) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology); + ID3D11DeviceContext_Draw(rendererData->d3dContext, (UINT)vertexCount, (UINT)vertexStart); +} + +static void D3D11_InvalidateCachedState(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + data->currentRenderTargetView = NULL; + data->currentRasterizerState = NULL; + data->currentBlendState = NULL; + data->currentShader = SHADER_NONE; + data->currentShaderResource = NULL; + data->currentSampler = NULL; + data->cliprectDirty = true; + data->viewportDirty = true; +} + +static bool D3D11_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->internal; + const int viewportRotation = D3D11_GetRotationForCurrentRenderTarget(renderer); + + if (!rendererData->d3dDevice) { + return SDL_SetError("Device lost and couldn't be recovered"); + } + + if (rendererData->pixelSizeChanged) { + D3D11_UpdateForWindowSizeChange(renderer); + rendererData->pixelSizeChanged = false; + } + + if (rendererData->currentViewportRotation != viewportRotation) { + rendererData->currentViewportRotation = viewportRotation; + rendererData->viewportDirty = true; + } + + if (!D3D11_UpdateVertexBuffer(renderer, vertices, vertsize)) { + return false; + } + + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_SETDRAWCOLOR: + { + break; // this isn't currently used in this render backend. + } + + case SDL_RENDERCMD_SETVIEWPORT: + { + SDL_Rect *viewport = &rendererData->currentViewport; + if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { + SDL_copyp(viewport, &cmd->data.viewport.rect); + rendererData->viewportDirty = true; + rendererData->cliprectDirty = true; + } + break; + } + + case SDL_RENDERCMD_SETCLIPRECT: + { + const SDL_Rect *rect = &cmd->data.cliprect.rect; + if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) { + rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled; + rendererData->cliprectDirty = true; + } + if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof(*rect)) != 0) { + SDL_copyp(&rendererData->currentCliprect, rect); + rendererData->cliprectDirty = true; + } + break; + } + + case SDL_RENDERCMD_CLEAR: + { + bool convert_color = SDL_RenderingLinearSpace(renderer); + SDL_FColor color = cmd->data.color.color; + if (convert_color) { + SDL_ConvertToLinear(&color); + } + color.r *= cmd->data.color.color_scale; + color.g *= cmd->data.color.color_scale; + color.b *= cmd->data.color.color_scale; + ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), &color.r); + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: + { + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + const size_t start = first / sizeof(D3D11_VertexPositionColor); + D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start, count); + break; + } + + case SDL_RENDERCMD_DRAW_LINES: + { + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + const size_t start = first / sizeof(D3D11_VertexPositionColor); + const D3D11_VertexPositionColor *verts = (D3D11_VertexPositionColor *)(((Uint8 *)vertices) + first); + D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count); + if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) { + D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count - 1), 1); + } + break; + } + + case SDL_RENDERCMD_FILL_RECTS: // unused + break; + + case SDL_RENDERCMD_COPY: // unused + break; + + case SDL_RENDERCMD_COPY_EX: // unused + break; + + case SDL_RENDERCMD_GEOMETRY: + { + SDL_Texture *texture = cmd->data.draw.texture; + const size_t count = cmd->data.draw.count; + const size_t first = cmd->data.draw.first; + const size_t start = first / sizeof(D3D11_VertexPositionColor); + + if (texture) { + D3D11_SetCopyState(renderer, cmd, NULL); + } else { + D3D11_SetDrawState(renderer, cmd, SHADER_SOLID, NULL, 0, NULL, NULL, NULL); + } + + D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, start, count); + break; + } + + case SDL_RENDERCMD_NO_OP: + break; + } + + cmd = cmd->next; + } + + return true; +} + +static SDL_Surface *D3D11_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + ID3D11RenderTargetView *renderTargetView = NULL; + ID3D11Texture2D *backBuffer = NULL; + ID3D11Texture2D *stagingTexture = NULL; + HRESULT result; + D3D11_TEXTURE2D_DESC stagingTextureDesc; + D3D11_RECT srcRect = { 0, 0, 0, 0 }; + D3D11_BOX srcBox; + D3D11_MAPPED_SUBRESOURCE textureMemory; + SDL_Surface *output = NULL; + + renderTargetView = D3D11_GetCurrentRenderTargetView(renderer); + if (!renderTargetView) { + SDL_SetError("%s, ID3D11DeviceContext::OMGetRenderTargets failed", __FUNCTION__); + goto done; + } + + ID3D11View_GetResource(renderTargetView, (ID3D11Resource **)&backBuffer); + if (!backBuffer) { + SDL_SetError("%s, ID3D11View::GetResource failed", __FUNCTION__); + goto done; + } + + // Create a staging texture to copy the screen's data to: + ID3D11Texture2D_GetDesc(backBuffer, &stagingTextureDesc); + stagingTextureDesc.Width = rect->w; + stagingTextureDesc.Height = rect->h; + stagingTextureDesc.BindFlags = 0; + stagingTextureDesc.MiscFlags = 0; + stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + stagingTextureDesc.Usage = D3D11_USAGE_STAGING; + result = ID3D11Device_CreateTexture2D(data->d3dDevice, + &stagingTextureDesc, + NULL, + &stagingTexture); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); + goto done; + } + + // Copy the desired portion of the back buffer to the staging texture: + if (!D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect, FALSE)) { + // D3D11_GetViewportAlignedD3DRect will have set the SDL error + goto done; + } + + srcBox.left = srcRect.left; + srcBox.right = srcRect.right; + srcBox.top = srcRect.top; + srcBox.bottom = srcRect.bottom; + srcBox.front = 0; + srcBox.back = 1; + ID3D11DeviceContext_CopySubresourceRegion(data->d3dContext, + (ID3D11Resource *)stagingTexture, + 0, + 0, 0, 0, + (ID3D11Resource *)backBuffer, + 0, + &srcBox); + + // Map the staging texture's data to CPU-accessible memory: + result = ID3D11DeviceContext_Map(data->d3dContext, + (ID3D11Resource *)stagingTexture, + 0, + D3D11_MAP_READ, + 0, + &textureMemory); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); + goto done; + } + + output = SDL_DuplicatePixels( + rect->w, rect->h, + D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), + renderer->target ? renderer->target->colorspace : renderer->output_colorspace, + textureMemory.pData, + textureMemory.RowPitch); + + // Unmap the texture: + ID3D11DeviceContext_Unmap(data->d3dContext, + (ID3D11Resource *)stagingTexture, + 0); + +done: + SAFE_RELEASE(backBuffer); + SAFE_RELEASE(stagingTexture); + return output; +} + +static bool D3D11_RenderPresent(SDL_Renderer *renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + HRESULT result; + DXGI_PRESENT_PARAMETERS parameters; + + if (!data->d3dDevice) { + return SDL_SetError("Device lost and couldn't be recovered"); + } + + SDL_zero(parameters); + + /* The application may optionally specify "dirty" or "scroll" + * rects to improve efficiency in certain scenarios. + */ + result = IDXGISwapChain1_Present1(data->swapChain, data->syncInterval, data->presentFlags, ¶meters); + + /* Discard the contents of the render target. + * This is a valid operation only when the existing contents will be entirely + * overwritten. If dirty or scroll rects are used, this call should be removed. + */ + ID3D11DeviceContext1_DiscardView(data->d3dContext, (ID3D11View *)data->mainRenderTargetView); + + // When the present flips, it unbinds the current view, so bind it again on the next draw call + data->currentRenderTargetView = NULL; + + if (FAILED(result) && result != DXGI_ERROR_WAS_STILL_DRAWING) { + /* If the device was removed either by a disconnect or a driver upgrade, we + * must recreate all device resources. + */ + if (result == DXGI_ERROR_DEVICE_REMOVED) { + if (D3D11_HandleDeviceLost(renderer)) { + SDL_SetError("Present failed, device lost"); + } else { + // Recovering from device lost failed, error is already set + } + } else if (result == DXGI_ERROR_INVALID_CALL) { + // We probably went through a fullscreen <-> windowed transition + D3D11_CreateWindowSizeDependentResources(renderer); + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::Present"), result); + } else { + WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::Present"), result); + } + return false; + } + return true; +} + +static bool D3D11_SetVSync(SDL_Renderer *renderer, const int vsync) +{ + D3D11_RenderData *data = (D3D11_RenderData *)renderer->internal; + + if (vsync < 0) { + return SDL_Unsupported(); + } + + if (vsync > 0) { + data->syncInterval = vsync; + data->presentFlags = 0; + } else { + data->syncInterval = 0; + data->presentFlags = DXGI_PRESENT_DO_NOT_WAIT; + } + return true; +} + +static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) +{ + D3D11_RenderData *data; + + HWND hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + if (!hwnd) { + return SDL_SetError("Couldn't get window handle"); + } + + SDL_SetupRendererColorspace(renderer, create_props); + + if (renderer->output_colorspace != SDL_COLORSPACE_SRGB && + renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR + /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) { + return SDL_SetError("Unsupported output colorspace"); + } + + data = (D3D11_RenderData *)SDL_calloc(1, sizeof(*data)); + if (!data) { + return false; + } + + data->identity = MatrixIdentity(); + + renderer->WindowEvent = D3D11_WindowEvent; + renderer->SupportsBlendMode = D3D11_SupportsBlendMode; + renderer->CreateTexture = D3D11_CreateTexture; + renderer->UpdateTexture = D3D11_UpdateTexture; +#ifdef SDL_HAVE_YUV + renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV; + renderer->UpdateTextureNV = D3D11_UpdateTextureNV; +#endif + renderer->LockTexture = D3D11_LockTexture; + renderer->UnlockTexture = D3D11_UnlockTexture; + renderer->SetTextureScaleMode = D3D11_SetTextureScaleMode; + renderer->SetRenderTarget = D3D11_SetRenderTarget; + renderer->QueueSetViewport = D3D11_QueueNoOp; + renderer->QueueSetDrawColor = D3D11_QueueNoOp; + renderer->QueueDrawPoints = D3D11_QueueDrawPoints; + renderer->QueueDrawLines = D3D11_QueueDrawPoints; // lines and points queue vertices the same way. + renderer->QueueGeometry = D3D11_QueueGeometry; + renderer->InvalidateCachedState = D3D11_InvalidateCachedState; + renderer->RunCommandQueue = D3D11_RunCommandQueue; + renderer->RenderReadPixels = D3D11_RenderReadPixels; + renderer->RenderPresent = D3D11_RenderPresent; + renderer->DestroyTexture = D3D11_DestroyTexture; + renderer->DestroyRenderer = D3D11_DestroyRenderer; + renderer->SetVSync = D3D11_SetVSync; + renderer->internal = data; + D3D11_InvalidateCachedState(renderer); + + renderer->name = D3D11_RenderDriver.name; + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); + SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); + + data->syncInterval = 0; + data->presentFlags = DXGI_PRESENT_DO_NOT_WAIT; + + /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in + * order to give init functions access to the underlying window handle: + */ + renderer->window = window; + + // Initialize Direct3D resources + if (FAILED(D3D11_CreateDeviceResources(renderer))) { + return false; + } + if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) { + return false; + } + + return true; +} + +SDL_RenderDriver D3D11_RenderDriver = { + D3D11_CreateRenderer, "direct3d11" +}; + +#endif // SDL_VIDEO_RENDER_D3D11 diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.c b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.c new file mode 100644 index 0000000..18965e2 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.c @@ -0,0 +1,116 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_RENDER_D3D11 + +#define COBJMACROS +#include "../../core/windows/SDL_windows.h" +#include + +#include "SDL_shaders_d3d11.h" + +#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str + +#if SDL_WINAPI_FAMILY_PHONE +#error Need to build shaders with level_9_3 +#endif + +// The shaders here were compiled with compile_shaders.bat + +#define g_main D3D11_PixelShader_Colors +#include "D3D11_PixelShader_Colors.h" +#undef g_main + +#define g_main D3D11_PixelShader_Textures +#include "D3D11_PixelShader_Textures.h" +#undef g_main + +#define g_main D3D11_PixelShader_Advanced +#include "D3D11_PixelShader_Advanced.h" +#undef g_main + +#define g_main D3D11_VertexShader +#include "D3D11_VertexShader.h" +#undef g_main + + +static struct +{ + const void *shader_data; + SIZE_T shader_size; +} D3D11_shaders[] = { + { NULL, 0 }, + { D3D11_PixelShader_Colors, sizeof(D3D11_PixelShader_Colors) }, + { D3D11_PixelShader_Textures, sizeof(D3D11_PixelShader_Textures) }, + { D3D11_PixelShader_Advanced, sizeof(D3D11_PixelShader_Advanced) }, +}; +SDL_COMPILE_TIME_ASSERT(D3D11_shaders, SDL_arraysize(D3D11_shaders) == NUM_SHADERS); + +bool D3D11_CreateVertexShader(ID3D11Device1 *d3dDevice, ID3D11VertexShader **vertexShader, ID3D11InputLayout **inputLayout) +{ + // Declare how the input layout for SDL's vertex shader will be setup: + const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = { + { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + HRESULT result; + + // Load in SDL's one and only vertex shader: + result = ID3D11Device_CreateVertexShader(d3dDevice, + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + NULL, + vertexShader); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateVertexShader"), result); + } + + // Create an input layout for SDL's vertex shader: + result = ID3D11Device_CreateInputLayout(d3dDevice, + vertexDesc, + ARRAYSIZE(vertexDesc), + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + inputLayout); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateInputLayout"), result); + } + return true; +} + +bool D3D11_CreatePixelShader(ID3D11Device1 *d3dDevice, D3D11_Shader shader, ID3D11PixelShader **pixelShader) +{ + HRESULT result; + + result = ID3D11Device_CreatePixelShader(d3dDevice, + D3D11_shaders[shader].shader_data, + D3D11_shaders[shader].shader_size, + NULL, + pixelShader); + if (FAILED(result)) { + return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreatePixelShader"), result); + } + return true; +} + +#endif // SDL_VIDEO_RENDER_D3D11 diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.h b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.h new file mode 100644 index 0000000..2279fb0 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/SDL_shaders_d3d11.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +// D3D11 shader implementation + +typedef enum +{ + SHADER_NONE, + SHADER_SOLID, + SHADER_RGB, + SHADER_ADVANCED, + NUM_SHADERS +} D3D11_Shader; + +extern bool D3D11_CreateVertexShader(ID3D11Device1 *d3dDevice, ID3D11VertexShader **vertexShader, ID3D11InputLayout **inputLayout); +extern bool D3D11_CreatePixelShader(ID3D11Device1 *d3dDevice, D3D11_Shader shader, ID3D11PixelShader **pixelShader); diff --git a/contrib/SDL-3.2.8/src/render/direct3d11/compile_shaders.bat b/contrib/SDL-3.2.8/src/render/direct3d11/compile_shaders.bat new file mode 100644 index 0000000..51d2a34 --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d11/compile_shaders.bat @@ -0,0 +1,4 @@ +fxc /T ps_4_0_level_9_1 /Fh D3D11_PixelShader_Colors.h D3D11_PixelShader_Colors.hlsl +fxc /T ps_4_0_level_9_1 /Fh D3D11_PixelShader_Textures.h D3D11_PixelShader_Textures.hlsl +fxc /T ps_5_0 /Fh D3D11_PixelShader_Advanced.h D3D11_PixelShader_Advanced.hlsl +fxc /T vs_4_0_level_9_1 /Fh D3D11_VertexShader.h D3D11_VertexShader.hlsl diff --git a/contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Advanced.h b/contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Advanced.h new file mode 100644 index 0000000..b8f40fe --- /dev/null +++ b/contrib/SDL-3.2.8/src/render/direct3d12/D3D12_PixelShader_Advanced.h @@ -0,0 +1,1389 @@ +#if 0 +; +; Input signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Position 0 xyzw 0 POS float +; TEXCOORD 0 xy 1 NONE float xy +; COLOR 0 xyzw 2 NONE float xyzw +; +; +; Output signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Target 0 xyzw 0 TARGET float xyzw +; +; shader hash: f6874446eaee41c102142c02d5bb3ab7 +; +; Pipeline Runtime Information: +; +; Pixel Shader +; DepthOutput=0 +; SampleFrequency=0 +; +; +; Input signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Position 0 noperspective +; TEXCOORD 0 linear +; COLOR 0 linear +; +; Output signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Target 0 +; +; Buffer Definitions: +; +; cbuffer Constants +; { +; +; struct Constants +; { +; +; float scRGB_output; ; Offset: 0 +; float texture_type; ; Offset: 4 +; float input_type; ; Offset: 8 +; float color_scale; ; Offset: 12 +; float tonemap_method; ; Offset: 16 +; float tonemap_factor1; ; Offset: 20 +; float tonemap_factor2; ; Offset: 24 +; float sdr_white_point; ; Offset: 28 +; float4 Yoffset; ; Offset: 32 +; float4 Rcoeff; ; Offset: 48 +; float4 Gcoeff; ; Offset: 64 +; float4 Bcoeff; ; Offset: 80 +; +; } Constants; ; Offset: 0 Size: 96 +; +; } +; +; +; Resource Bindings: +; +; Name Type Format Dim ID HLSL Bind Count +; ------------------------------ ---------- ------- ----------- ------- -------------- ------ +; Constants cbuffer NA NA CB0 cb1 1 +; sampler0 sampler NA NA S0 s0 1 +; texture0 texture f32 2d T0 t0 1 +; texture1 texture f32 2d T1 t1 1 +; texture2 texture f32 2d T2 t2 1 +; +; +; ViewId state: +; +; Number of inputs: 12, outputs: 4 +; Outputs dependent on ViewId: { } +; Inputs contributing to computation of Outputs: +; output 0 depends on inputs: { 4, 5, 8 } +; output 1 depends on inputs: { 4, 5, 9 } +; output 2 depends on inputs: { 4, 5, 10 } +; output 3 depends on inputs: { 4, 5, 11 } +; +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +%dx.types.Handle = type { i8* } +%dx.types.CBufRet.f32 = type { float, float, float, float } +%dx.types.ResRet.f32 = type { float, float, float, float, i32 } +%"class.Texture2D >" = type { <4 x float>, %"class.Texture2D >::mips_type" } +%"class.Texture2D >::mips_type" = type { i32 } +%Constants = type { float, float, float, float, float, float, float, float, <4 x float>, <4 x float>, <4 x float>, <4 x float> } +%struct.SamplerState = type { i32 } + +define void @main() { + %1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 2, i32 2, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %2 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 1, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %3 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 0, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %4 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 3, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %5 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 1, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %6 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %7 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %8 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %9 = call float @dx.op.loadInput.f32(i32 4, i32 2, i32 0, i8 3, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %10 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %11 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 1, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %12 = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %5, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %13 = extractvalue %dx.types.CBufRet.f32 %12, 1 + %14 = fcmp fast oeq float %13, 0.000000e+00 + br i1 %14, label %114, label %15 + +;