Implemented more flexible blending modes for accelerated renderers

This fixes bug 2594 - Propose new blend mode, SDL_BLENDMODE_BLEND_DSTA

	blendMode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA,
	                                       SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
	                                       SDL_BLENDOPERATION_ADD,
	                                       SDL_BLENDFACTOR_ZERO,
	                                       SDL_BLENDFACTOR_ONE,
	                                       SDL_BLENDOPERATION_ADD);

This fixes bug 2828 - Subtractive Blending

	blendMode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA,
	                                       SDL_BLENDFACTOR_ONE,
	                                       SDL_BLENDOPERATION_SUBTRACT,
	                                       SDL_BLENDFACTOR_ZERO,
	                                       SDL_BLENDFACTOR_ONE,
	                                       SDL_BLENDOPERATION_SUBTRACT);


This goes partway to fixing bug 3684 - Add support for a pre-multiplied alpha blending mode

	blendMode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE,
	                                       SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
	                                       SDL_BLENDOPERATION_ADD,
	                                       SDL_BLENDFACTOR_ONE,
	                                       SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
	                                       SDL_BLENDOPERATION_ADD);
This commit is contained in:
Sam Lantinga 2017-08-14 05:51:44 -07:00
parent f8e1874d01
commit c59d9923b3
16 changed files with 718 additions and 778 deletions

View file

@ -56,6 +56,7 @@ static SDL_Renderer *GLES_CreateRenderer(SDL_Window * window, Uint32 flags);
static void GLES_WindowEvent(SDL_Renderer * renderer,
const SDL_WindowEvent *event);
static int GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h);
static SDL_bool GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode);
static int GLES_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static int GLES_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels,
@ -116,7 +117,7 @@ typedef struct
SDL_GLContext context;
struct {
Uint32 color;
int blendMode;
SDL_BlendMode blendMode;
SDL_bool tex_coords;
} current;
@ -130,6 +131,8 @@ typedef struct
GLuint window_framebuffer;
SDL_bool GL_OES_blend_func_separate_supported;
SDL_bool GL_OES_blend_equation_separate_supported;
SDL_bool GL_OES_blend_subtract_supported;
} GLES_RenderData;
typedef struct
@ -262,7 +265,7 @@ GLES_ResetState(SDL_Renderer *renderer)
}
data->current.color = 0xffffffff;
data->current.blendMode = -1;
data->current.blendMode = SDL_BLENDMODE_INVALID;
data->current.tex_coords = SDL_FALSE;
data->glDisable(GL_DEPTH_TEST);
@ -319,6 +322,7 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
renderer->WindowEvent = GLES_WindowEvent;
renderer->GetOutputSize = GLES_GetOutputSize;
renderer->SupportsBlendMode = GLES_SupportsBlendMode;
renderer->CreateTexture = GLES_CreateTexture;
renderer->UpdateTexture = GLES_UpdateTexture;
renderer->LockTexture = GLES_LockTexture;
@ -388,6 +392,12 @@ GLES_CreateRenderer(SDL_Window * window, Uint32 flags)
if (SDL_GL_ExtensionSupported("GL_OES_blend_func_separate")) {
data->GL_OES_blend_func_separate_supported = SDL_TRUE;
}
if (SDL_GL_ExtensionSupported("GL_OES_blend_equation_separate")) {
data->GL_OES_blend_equation_separate_supported = SDL_TRUE;
}
if (SDL_GL_ExtensionSupported("GL_OES_blend_subtract")) {
data->GL_OES_blend_subtract_supported = SDL_TRUE;
}
/* Set up parameters for rendering */
GLES_ResetState(renderer);
@ -430,6 +440,79 @@ GLES_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
return 0;
}
static GLenum GetBlendFunc(SDL_BlendFactor factor)
{
switch (factor) {
case SDL_BLENDFACTOR_ZERO:
return GL_ZERO;
case SDL_BLENDFACTOR_ONE:
return GL_ONE;
case SDL_BLENDFACTOR_SRC_COLOR:
return GL_SRC_COLOR;
case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
return GL_ONE_MINUS_SRC_COLOR;
case SDL_BLENDFACTOR_SRC_ALPHA:
return GL_SRC_ALPHA;
case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
return GL_ONE_MINUS_SRC_ALPHA;
case SDL_BLENDFACTOR_DST_COLOR:
return GL_DST_COLOR;
case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
return GL_ONE_MINUS_DST_COLOR;
case SDL_BLENDFACTOR_DST_ALPHA:
return GL_DST_ALPHA;
case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
return GL_ONE_MINUS_DST_ALPHA;
default:
return GL_INVALID_ENUM;
}
}
static GLenum GetBlendEquation(SDL_BlendOperation operation)
{
switch (operation) {
case SDL_BLENDOPERATION_ADD:
return GL_FUNC_ADD_OES;
case SDL_BLENDOPERATION_SUBTRACT:
return GL_FUNC_SUBTRACT_OES;
case SDL_BLENDOPERATION_REV_SUBTRACT:
return GL_FUNC_REVERSE_SUBTRACT_OES;
default:
return GL_INVALID_ENUM;
}
}
static SDL_bool
GLES_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
{
GLES_RenderData *data = (GLES_RenderData *) renderer->driverdata;
SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
if (GetBlendFunc(srcColorFactor) == GL_INVALID_ENUM ||
GetBlendFunc(srcAlphaFactor) == GL_INVALID_ENUM ||
GetBlendEquation(colorOperation) == GL_INVALID_ENUM ||
GetBlendFunc(dstColorFactor) == GL_INVALID_ENUM ||
GetBlendFunc(dstAlphaFactor) == GL_INVALID_ENUM ||
GetBlendEquation(alphaOperation) == GL_INVALID_ENUM) {
return SDL_FALSE;
}
if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->GL_OES_blend_func_separate_supported) {
return SDL_FALSE;
}
if (colorOperation != alphaOperation && !data->GL_OES_blend_equation_separate_supported) {
return SDL_FALSE;
}
if (colorOperation != SDL_BLENDOPERATION_ADD && !data->GL_OES_blend_subtract_supported) {
return SDL_FALSE;
}
return SDL_TRUE;
}
static SDL_INLINE int
power_of_2(int input)
{
@ -739,37 +822,28 @@ GLES_SetColor(GLES_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
}
static void
GLES_SetBlendMode(GLES_RenderData * data, int blendMode)
GLES_SetBlendMode(GLES_RenderData * data, SDL_BlendMode blendMode)
{
if (blendMode != data->current.blendMode) {
switch (blendMode) {
case SDL_BLENDMODE_NONE:
if (blendMode == SDL_BLENDMODE_NONE) {
data->glDisable(GL_BLEND);
break;
case SDL_BLENDMODE_BLEND:
} else {
data->glEnable(GL_BLEND);
if (data->GL_OES_blend_func_separate_supported) {
data->glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
data->glBlendFuncSeparateOES(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
} else {
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
data->glBlendFunc(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)));
}
break;
case SDL_BLENDMODE_ADD:
data->glEnable(GL_BLEND);
if (data->GL_OES_blend_func_separate_supported) {
data->glBlendFuncSeparateOES(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
} else {
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
if (data->GL_OES_blend_equation_separate_supported) {
data->glBlendEquationSeparateOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)),
GetBlendEquation(SDL_GetBlendModeAlphaOperation(blendMode)));
} else if (data->GL_OES_blend_subtract_supported) {
data->glBlendEquationOES(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)));
}
break;
case SDL_BLENDMODE_MOD:
data->glEnable(GL_BLEND);
if (data->GL_OES_blend_func_separate_supported) {
data->glBlendFuncSeparateOES(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
} else {
data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
}
break;
}
data->current.blendMode = blendMode;
}