mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-05-31 08:57:40 +00:00
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:
parent
f8e1874d01
commit
c59d9923b3
16 changed files with 718 additions and 778 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue