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

@ -122,7 +122,6 @@ typedef struct GLES2_ShaderCache
typedef struct GLES2_ProgramCacheEntry
{
GLuint id;
SDL_BlendMode blend_mode;
GLES2_ShaderCacheEntry *vertex_shader;
GLES2_ShaderCacheEntry *fragment_shader;
GLuint uniform_locations[16];
@ -177,7 +176,7 @@ typedef struct GLES2_DriverContext
SDL_bool debug_enabled;
struct {
int blendMode;
SDL_BlendMode blendMode;
SDL_bool tex_coords;
} current;
@ -372,6 +371,70 @@ GLES2_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;
case SDL_BLENDOPERATION_SUBTRACT:
return GL_FUNC_SUBTRACT;
case SDL_BLENDOPERATION_REV_SUBTRACT:
return GL_FUNC_REVERSE_SUBTRACT;
default:
return GL_INVALID_ENUM;
}
}
static SDL_bool
GLES2_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
{
GLES2_DriverContext *data = (GLES2_DriverContext *) 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;
}
return SDL_TRUE;
}
static int
GLES2_UpdateViewport(SDL_Renderer * renderer)
{
@ -882,19 +945,16 @@ GLES2_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
* Shader management functions *
*************************************************************************************************/
static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type,
SDL_BlendMode blendMode);
static GLES2_ShaderCacheEntry *GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type);
static void GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry);
static GLES2_ProgramCacheEntry *GLES2_CacheProgram(SDL_Renderer *renderer,
GLES2_ShaderCacheEntry *vertex,
GLES2_ShaderCacheEntry *fragment,
SDL_BlendMode blendMode);
static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source,
SDL_BlendMode blendMode);
GLES2_ShaderCacheEntry *fragment);
static int GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source);
static GLES2_ProgramCacheEntry *
GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
GLES2_ShaderCacheEntry *fragment, SDL_BlendMode blendMode)
GLES2_ShaderCacheEntry *fragment)
{
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_ProgramCacheEntry *entry;
@ -933,7 +993,6 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
}
entry->vertex_shader = vertex;
entry->fragment_shader = fragment;
entry->blend_mode = blendMode;
/* Create the program and link it */
entry->id = data->glCreateProgram();
@ -1011,7 +1070,7 @@ GLES2_CacheProgram(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *vertex,
}
static GLES2_ShaderCacheEntry *
GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode blendMode)
GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type)
{
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
const GLES2_Shader *shader;
@ -1021,7 +1080,7 @@ GLES2_CacheShader(SDL_Renderer *renderer, GLES2_ShaderType type, SDL_BlendMode b
int i, j;
/* Find the corresponding shader */
shader = GLES2_GetShader(type, blendMode);
shader = GLES2_GetShader(type);
if (!shader) {
SDL_SetError("No shader matching the requested characteristics was found");
return NULL;
@ -1130,7 +1189,7 @@ GLES2_EvictShader(SDL_Renderer *renderer, GLES2_ShaderCacheEntry *entry)
}
static int
GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendMode blendMode)
GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source)
{
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_ShaderCacheEntry *vertex = NULL;
@ -1170,11 +1229,11 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendM
}
/* Load the requested shaders */
vertex = GLES2_CacheShader(renderer, vtype, blendMode);
vertex = GLES2_CacheShader(renderer, vtype);
if (!vertex) {
goto fault;
}
fragment = GLES2_CacheShader(renderer, ftype, blendMode);
fragment = GLES2_CacheShader(renderer, ftype);
if (!fragment) {
goto fault;
}
@ -1187,7 +1246,7 @@ GLES2_SelectProgram(SDL_Renderer *renderer, GLES2_ImageSource source, SDL_BlendM
}
/* Generate a matching program */
program = GLES2_CacheProgram(renderer, vertex, fragment, blendMode);
program = GLES2_CacheProgram(renderer, vertex, fragment);
if (!program) {
goto fault;
}
@ -1341,26 +1400,19 @@ GLES2_RenderClear(SDL_Renderer * renderer)
}
static void
GLES2_SetBlendMode(GLES2_DriverContext *data, int blendMode)
GLES2_SetBlendMode(GLES2_DriverContext *data, SDL_BlendMode blendMode)
{
if (blendMode != data->current.blendMode) {
switch (blendMode) {
default:
case SDL_BLENDMODE_NONE:
if (blendMode == SDL_BLENDMODE_NONE) {
data->glDisable(GL_BLEND);
break;
case SDL_BLENDMODE_BLEND:
} else {
data->glEnable(GL_BLEND);
data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
break;
case SDL_BLENDMODE_ADD:
data->glEnable(GL_BLEND);
data->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
case SDL_BLENDMODE_MOD:
data->glEnable(GL_BLEND);
data->glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE);
break;
data->glBlendFuncSeparate(GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeDstColorFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blendMode)),
GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blendMode)));
data->glBlendEquationSeparate(GetBlendEquation(SDL_GetBlendModeColorOperation(blendMode)),
GetBlendEquation(SDL_GetBlendModeAlphaOperation(blendMode)));
}
data->current.blendMode = blendMode;
}
@ -1383,18 +1435,17 @@ static int
GLES2_SetDrawingState(SDL_Renderer * renderer)
{
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
const int blendMode = renderer->blendMode;
GLES2_ProgramCacheEntry *program;
Uint8 r, g, b, a;
GLES2_ActivateRenderer(renderer);
GLES2_SetBlendMode(data, blendMode);
GLES2_SetBlendMode(data, renderer->blendMode);
GLES2_SetTexCoords(data, SDL_FALSE);
/* Activate an appropriate shader and set the projection matrix */
if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID, blendMode) < 0) {
if (GLES2_SelectProgram(renderer, GLES2_IMAGESOURCE_SOLID) < 0) {
return -1;
}
@ -1555,12 +1606,10 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
GLES2_DriverContext *data = (GLES2_DriverContext *)renderer->driverdata;
GLES2_TextureData *tdata = (GLES2_TextureData *)texture->driverdata;
GLES2_ImageSource sourceType = GLES2_IMAGESOURCE_TEXTURE_ABGR;
SDL_BlendMode blendMode;
GLES2_ProgramCacheEntry *program;
Uint8 r, g, b, a;
/* Activate an appropriate shader and set the projection matrix */
blendMode = texture->blendMode;
if (renderer->target) {
/* Check if we need to do color mapping between the source and render target textures */
if (renderer->target->format != texture->format) {
@ -1658,7 +1707,7 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
}
}
if (GLES2_SelectProgram(renderer, sourceType, blendMode) < 0) {
if (GLES2_SelectProgram(renderer, sourceType) < 0) {
return -1;
}
@ -1705,7 +1754,7 @@ GLES2_SetupCopy(SDL_Renderer *renderer, SDL_Texture *texture)
}
/* Configure texture blending */
GLES2_SetBlendMode(data, blendMode);
GLES2_SetBlendMode(data, renderer->blendMode);
GLES2_SetTexCoords(data, SDL_TRUE);
return 0;
@ -1938,7 +1987,7 @@ GLES2_ResetState(SDL_Renderer *renderer)
GLES2_ActivateRenderer(renderer);
}
data->current.blendMode = -1;
data->current.blendMode = SDL_BLENDMODE_INVALID;
data->current.tex_coords = SDL_FALSE;
data->glActiveTexture(GL_TEXTURE0);
@ -2091,28 +2140,29 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
data->window_framebuffer = (GLuint)window_framebuffer;
/* Populate the function pointers for the module */
renderer->WindowEvent = &GLES2_WindowEvent;
renderer->GetOutputSize = &GLES2_GetOutputSize;
renderer->CreateTexture = &GLES2_CreateTexture;
renderer->UpdateTexture = &GLES2_UpdateTexture;
renderer->UpdateTextureYUV = &GLES2_UpdateTextureYUV;
renderer->LockTexture = &GLES2_LockTexture;
renderer->UnlockTexture = &GLES2_UnlockTexture;
renderer->SetRenderTarget = &GLES2_SetRenderTarget;
renderer->UpdateViewport = &GLES2_UpdateViewport;
renderer->UpdateClipRect = &GLES2_UpdateClipRect;
renderer->RenderClear = &GLES2_RenderClear;
renderer->RenderDrawPoints = &GLES2_RenderDrawPoints;
renderer->RenderDrawLines = &GLES2_RenderDrawLines;
renderer->RenderFillRects = &GLES2_RenderFillRects;
renderer->RenderCopy = &GLES2_RenderCopy;
renderer->RenderCopyEx = &GLES2_RenderCopyEx;
renderer->RenderReadPixels = &GLES2_RenderReadPixels;
renderer->RenderPresent = &GLES2_RenderPresent;
renderer->DestroyTexture = &GLES2_DestroyTexture;
renderer->DestroyRenderer = &GLES2_DestroyRenderer;
renderer->GL_BindTexture = &GLES2_BindTexture;
renderer->GL_UnbindTexture = &GLES2_UnbindTexture;
renderer->WindowEvent = GLES2_WindowEvent;
renderer->GetOutputSize = GLES2_GetOutputSize;
renderer->SupportsBlendMode = GLES2_SupportsBlendMode;
renderer->CreateTexture = GLES2_CreateTexture;
renderer->UpdateTexture = GLES2_UpdateTexture;
renderer->UpdateTextureYUV = GLES2_UpdateTextureYUV;
renderer->LockTexture = GLES2_LockTexture;
renderer->UnlockTexture = GLES2_UnlockTexture;
renderer->SetRenderTarget = GLES2_SetRenderTarget;
renderer->UpdateViewport = GLES2_UpdateViewport;
renderer->UpdateClipRect = GLES2_UpdateClipRect;
renderer->RenderClear = GLES2_RenderClear;
renderer->RenderDrawPoints = GLES2_RenderDrawPoints;
renderer->RenderDrawLines = GLES2_RenderDrawLines;
renderer->RenderFillRects = GLES2_RenderFillRects;
renderer->RenderCopy = GLES2_RenderCopy;
renderer->RenderCopyEx = GLES2_RenderCopyEx;
renderer->RenderReadPixels = GLES2_RenderReadPixels;
renderer->RenderPresent = GLES2_RenderPresent;
renderer->DestroyTexture = GLES2_DestroyTexture;
renderer->DestroyRenderer = GLES2_DestroyRenderer;
renderer->GL_BindTexture = GLES2_BindTexture;
renderer->GL_UnbindTexture = GLES2_UnbindTexture;
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;