diff --git a/include/SDL3/SDL_blendmode.h b/include/SDL3/SDL_blendmode.h index 84cf622cb7..ba6de3e4a0 100644 --- a/include/SDL3/SDL_blendmode.h +++ b/include/SDL3/SDL_blendmode.h @@ -96,7 +96,11 @@ typedef enum SDL_BlendFactor SDL_BLENDFACTOR_DST_COLOR = 0x7, /**< dstR, dstG, dstB, dstA */ SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */ SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */ - SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */ + SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA, /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */ + SDL_BLENDFACTOR_SRC1_COLOR = 0xB, /**< src1R, src1G, src1B, src1A */ + SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR = 0xC, /**< 1-src1R, 1-src1G, 1-src1B, 1-src1A */ + SDL_BLENDFACTOR_SRC1_ALPHA = 0xD, /**< src1A, src1A, src1A, src1A */ + SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA = 0xE /**< 1-src1A, 1-src1A, 1-src1A, 1-src1A */ } SDL_BlendFactor; /** diff --git a/include/SDL3/SDL_gpu.h b/include/SDL3/SDL_gpu.h index 065c00bc65..74769fef0a 100644 --- a/include/SDL3/SDL_gpu.h +++ b/include/SDL3/SDL_gpu.h @@ -1246,7 +1246,11 @@ typedef enum SDL_GPUBlendFactor SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_ALPHA, /**< 1 - destination alpha */ SDL_GPU_BLENDFACTOR_CONSTANT_COLOR, /**< blend constant */ SDL_GPU_BLENDFACTOR_ONE_MINUS_CONSTANT_COLOR, /**< 1 - blend constant */ - SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE /**< min(source alpha, 1 - destination alpha) */ + SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE, /**< min(source alpha, 1 - destination alpha) */ + SDL_GPU_BLENDFACTOR_SRC1_COLOR, /**< second source color */ + SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC1_COLOR, /**< 1 - second source color */ + SDL_GPU_BLENDFACTOR_SRC1_ALPHA, /**< second source alpha */ + SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA /**< 1 - second source alpha */ } SDL_GPUBlendFactor; /** @@ -2281,6 +2285,12 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( * SDL_GPUSamplerCreateInfo must be set to false. Disabling optional * features allows the application to run on some older Android devices. * Defaults to true. + * - `SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DUAL_SOURCE_BLENDING_BOOLEAN`: Enable + * Vulkan device feature dualSrcBlend. If disabled, dual source blend factors + * (SDL_BLENDFACTOR_SRC1_COLOR, SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR, + * SDL_BLENDFACTOR_SRC1_ALPHA, SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA) are not + * supported. Disabling optional features allows the application to run on + * some older Android devices. Defaults to false. * * These are the current shader format properties: * @@ -2370,6 +2380,7 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( #define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN "SDL.gpu.device.create.feature.depth_clamping" #define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN "SDL.gpu.device.create.feature.indirect_draw_first_instance" #define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN "SDL.gpu.device.create.feature.anisotropy" +#define SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DUAL_SOURCE_BLENDING_BOOLEAN "SDL.gpu.device.create.feature.dual_source_blending" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN "SDL.gpu.device.create.shaders.private" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN "SDL.gpu.device.create.shaders.spirv" #define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN "SDL.gpu.device.create.shaders.dxbc" diff --git a/src/gpu/SDL_sysgpu.h b/src/gpu/SDL_sysgpu.h index 604be78b5b..1abe5ea7ef 100644 --- a/src/gpu/SDL_sysgpu.h +++ b/src/gpu/SDL_sysgpu.h @@ -150,7 +150,7 @@ typedef struct BlitPipelineCacheEntry #define SDL_GPU_COMPAREOP_MAX_ENUM_VALUE (SDL_GPU_COMPAREOP_ALWAYS + 1) #define SDL_GPU_STENCILOP_MAX_ENUM_VALUE (SDL_GPU_STENCILOP_DECREMENT_AND_WRAP + 1) #define SDL_GPU_BLENDOP_MAX_ENUM_VALUE (SDL_GPU_BLENDOP_MAX + 1) -#define SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE (SDL_GPU_BLENDFACTOR_SRC_ALPHA_SATURATE + 1) +#define SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE (SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA + 1) #define SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE (SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084 + 1) #define SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE (SDL_GPU_PRESENTMODE_MAILBOX + 1) diff --git a/src/gpu/d3d12/SDL_gpu_d3d12.c b/src/gpu/d3d12/SDL_gpu_d3d12.c index e7fefa3e81..9bc311a62c 100644 --- a/src/gpu/d3d12/SDL_gpu_d3d12.c +++ b/src/gpu/d3d12/SDL_gpu_d3d12.c @@ -241,6 +241,10 @@ static D3D12_BLEND SDLToD3D12_BlendFactor[] = { D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE + D3D12_BLEND_SRC1_COLOR, // SRC1_COLOR + D3D12_BLEND_INV_SRC1_COLOR, // ONE_MINUS_SRC1_COLOR + D3D12_BLEND_SRC1_ALPHA, // SRC1_ALPHA + D3D12_BLEND_INV_SRC1_ALPHA, // ONE_MINUS_SRC1_ALPHA }; SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactor, SDL_arraysize(SDLToD3D12_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); @@ -259,6 +263,10 @@ static D3D12_BLEND SDLToD3D12_BlendFactorAlpha[] = { D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE + D3D12_BLEND_SRC1_ALPHA, // SRC1_COLOR + D3D12_BLEND_INV_SRC1_ALPHA, // ONE_MINUS_SRC1_COLOR + D3D12_BLEND_SRC1_ALPHA, // SRC1_ALPHA + D3D12_BLEND_INV_SRC1_ALPHA, // ONE_MINUS_SRC1_ALPHA }; SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactorAlpha, SDL_arraysize(SDLToD3D12_BlendFactorAlpha) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); diff --git a/src/gpu/metal/SDL_gpu_metal.m b/src/gpu/metal/SDL_gpu_metal.m index de6c7b7fc8..78c84b17ba 100644 --- a/src/gpu/metal/SDL_gpu_metal.m +++ b/src/gpu/metal/SDL_gpu_metal.m @@ -291,6 +291,10 @@ static MTLBlendFactor SDLToMetal_BlendFactor[] = { MTLBlendFactorBlendColor, // CONSTANT_COLOR MTLBlendFactorOneMinusBlendColor, // ONE_MINUS_CONSTANT_COLOR MTLBlendFactorSourceAlphaSaturated, // SRC_ALPHA_SATURATE + MTLBlendFactorSource1Color, // SRC1_COLOR + MTLBlendFactorOneMinusSource1Color, // ONE_MINUS_SRC1_COLOR + MTLBlendFactorSource1Alpha, // SRC1_ALPHA + MTLBlendFactorOneMinusSource1Alpha, // ONE_MINUS_SRC1_ALPHA }; SDL_COMPILE_TIME_ASSERT(SDLToMetal_BlendFactor, SDL_arraysize(SDLToMetal_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 3b9efe5c45..8fb4a88e1e 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -387,7 +387,11 @@ static VkBlendFactor SDLToVK_BlendFactor[] = { VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE + VK_BLEND_FACTOR_SRC_ALPHA_SATURATE, + VK_BLEND_FACTOR_SRC1_COLOR, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, + VK_BLEND_FACTOR_SRC1_ALPHA, + VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA }; SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendFactor, SDL_arraysize(SDLToVK_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); @@ -12326,7 +12330,8 @@ static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( (!deviceFeatures.shaderClipDistance && features->desiredVulkan10DeviceFeatures.shaderClipDistance) || (!deviceFeatures.drawIndirectFirstInstance && features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance) || (!deviceFeatures.sampleRateShading && features->desiredVulkan10DeviceFeatures.sampleRateShading) || - (!deviceFeatures.samplerAnisotropy && features->desiredVulkan10DeviceFeatures.samplerAnisotropy)) { + (!deviceFeatures.samplerAnisotropy && features->desiredVulkan10DeviceFeatures.samplerAnisotropy) || + (!deviceFeatures.dualSrcBlend && features->desiredVulkan10DeviceFeatures.dualSrcBlend)) { return 0; } @@ -12838,6 +12843,7 @@ static bool VULKAN_INTERNAL_PrepareVulkan( features->desiredVulkan10DeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE; features->desiredVulkan10DeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; + features->desiredVulkan10DeviceFeatures.dualSrcBlend = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DUAL_SOURCE_BLENDING_BOOLEAN, false) ? VK_TRUE : VK_FALSE; // These features have near universal support so they are always enabled features->desiredVulkan10DeviceFeatures.independentBlend = VK_TRUE; diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index edb0be613a..445ee1a7d9 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -421,6 +421,14 @@ static D3D11_BLEND GetBlendFunc(SDL_BlendFactor factor) return D3D11_BLEND_DEST_ALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA; + case SDL_BLENDFACTOR_SRC1_COLOR: + return D3D11_BLEND_SRC1_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR: + return D3D11_BLEND_INV_SRC1_COLOR; + case SDL_BLENDFACTOR_SRC1_ALPHA: + return D3D11_BLEND_SRC1_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA: + return D3D11_BLEND_INV_SRC1_ALPHA; default: return (D3D11_BLEND)0; } diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c index d88903c6f6..d66dd4fd18 100644 --- a/src/render/direct3d12/SDL_render_d3d12.c +++ b/src/render/direct3d12/SDL_render_d3d12.c @@ -611,6 +611,14 @@ static D3D12_BLEND GetBlendFunc(SDL_BlendFactor factor) return D3D12_BLEND_DEST_ALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3D12_BLEND_INV_DEST_ALPHA; + case SDL_BLENDFACTOR_SRC1_COLOR: + return D3D12_BLEND_SRC1_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR: + return D3D12_BLEND_INV_SRC1_COLOR; + case SDL_BLENDFACTOR_SRC1_ALPHA: + return D3D12_BLEND_SRC1_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA: + return D3D12_BLEND_INV_SRC1_ALPHA; default: return (D3D12_BLEND)0; } diff --git a/src/render/gpu/SDL_gpu_util.h b/src/render/gpu/SDL_gpu_util.h index 4062390915..a5bd629a1a 100644 --- a/src/render/gpu/SDL_gpu_util.h +++ b/src/render/gpu/SDL_gpu_util.h @@ -48,6 +48,14 @@ static SDL_INLINE SDL_GPUBlendFactor GPU_ConvertBlendFactor(SDL_BlendFactor fact return SDL_GPU_BLENDFACTOR_DST_ALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return SDL_GPU_BLENDFACTOR_ONE_MINUS_DST_ALPHA; + case SDL_BLENDFACTOR_SRC1_COLOR: + return SDL_GPU_BLENDFACTOR_SRC1_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR: + return SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC1_COLOR; + case SDL_BLENDFACTOR_SRC1_ALPHA: + return SDL_GPU_BLENDFACTOR_SRC1_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA: + return SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA; default: return SDL_GPU_BLENDFACTOR_INVALID; } diff --git a/src/render/gpu/SDL_render_gpu.c b/src/render/gpu/SDL_render_gpu.c index 0884d686ca..84c74a4e67 100644 --- a/src/render/gpu/SDL_render_gpu.c +++ b/src/render/gpu/SDL_render_gpu.c @@ -1771,6 +1771,9 @@ static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN)) { SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, false); } + if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DUAL_SOURCE_BLENDING_BOOLEAN)) { + SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DUAL_SOURCE_BLENDING_BOOLEAN, false); + } // These properties allow using the renderer on more macOS devices. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN)) { SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN, false); diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 64402dae85..03047906a3 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -371,6 +371,14 @@ static GLenum GetBlendFunc(SDL_BlendFactor factor) return GL_DST_ALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case SDL_BLENDFACTOR_SRC1_COLOR: + return GL_SRC1_COLOR; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR: + return GL_ONE_MINUS_SRC1_COLOR; + case SDL_BLENDFACTOR_SRC1_ALPHA: + return GL_SRC1_ALPHA; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA: + return GL_ONE_MINUS_SRC1_ALPHA; default: return GL_INVALID_ENUM; } diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index a37f2b1b74..d412ea9c24 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -342,6 +342,14 @@ static GLenum GetBlendFunc(SDL_BlendFactor factor) return GL_DST_ALPHA; case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA; + case SDL_BLENDFACTOR_SRC1_COLOR: + return GL_SRC1_COLOR_EXT; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_COLOR: + return GL_ONE_MINUS_SRC1_COLOR_EXT; + case SDL_BLENDFACTOR_SRC1_ALPHA: + return GL_SRC1_ALPHA_EXT; + case SDL_BLENDFACTOR_ONE_MINUS_SRC1_ALPHA: + return GL_ONE_MINUS_SRC1_ALPHA_EXT; default: return GL_INVALID_ENUM; }