mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-31 22:42:52 +08:00
[N-Gage] Simplify rendering back-end; more micro-optimization
- Remove redundant null checks - Use cached texture properties instead of API calls (GetBitmapWidth/Height/Pitch) - Eliminate duplicate SDL_GetRenderScale() call in Copy() - Reorder CopyEx() fast paths to check no-transform case first - Combine operations in NGAGE_ConvertColor() to reduce intermediate steps
This commit is contained in:
@@ -82,7 +82,7 @@ void NGAGE_DestroyTextureData(NGAGE_TextureData *data)
|
|||||||
|
|
||||||
void *NGAGE_GetBitmapDataAddress(NGAGE_TextureData *data)
|
void *NGAGE_GetBitmapDataAddress(NGAGE_TextureData *data)
|
||||||
{
|
{
|
||||||
if (data && data->bitmap) {
|
if (data) {
|
||||||
return data->bitmap->DataAddress();
|
return data->bitmap->DataAddress();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -90,25 +90,24 @@ void *NGAGE_GetBitmapDataAddress(NGAGE_TextureData *data)
|
|||||||
|
|
||||||
int NGAGE_GetBitmapPitch(NGAGE_TextureData *data)
|
int NGAGE_GetBitmapPitch(NGAGE_TextureData *data)
|
||||||
{
|
{
|
||||||
if (data && data->bitmap) {
|
if (data) {
|
||||||
TSize size = data->bitmap->SizeInPixels();
|
return data->cachedPitch;
|
||||||
return data->bitmap->ScanLineLength(size.iWidth, data->bitmap->DisplayMode());
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NGAGE_GetBitmapWidth(NGAGE_TextureData *data)
|
int NGAGE_GetBitmapWidth(NGAGE_TextureData *data)
|
||||||
{
|
{
|
||||||
if (data && data->bitmap) {
|
if (data) {
|
||||||
return data->bitmap->SizeInPixels().iWidth;
|
return data->cachedWidth;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NGAGE_GetBitmapHeight(NGAGE_TextureData *data)
|
int NGAGE_GetBitmapHeight(NGAGE_TextureData *data)
|
||||||
{
|
{
|
||||||
if (data && data->bitmap) {
|
if (data) {
|
||||||
return data->bitmap->SizeInPixels().iHeight;
|
return data->cachedHeight;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -140,10 +139,8 @@ void NGAGE_SetClipRect(const SDL_Rect *rect)
|
|||||||
|
|
||||||
void NGAGE_SetDrawColor(const Uint32 color)
|
void NGAGE_SetDrawColor(const Uint32 color)
|
||||||
{
|
{
|
||||||
if (gRenderer) {
|
|
||||||
gRenderer->SetDrawColor(color);
|
gRenderer->SetDrawColor(color);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void NGAGE_PumpEventsInternal()
|
void NGAGE_PumpEventsInternal()
|
||||||
{
|
{
|
||||||
@@ -177,7 +174,9 @@ CRenderer *CRenderer::NewL()
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0), iWorkBuffer1(0), iWorkBuffer2(0), iWorkBufferSize(0), iTempRenderBitmap(0), iTempRenderBitmapWidth(0), iTempRenderBitmapHeight(0), iLastColorR(-1), iLastColorG(-1), iLastColorB(-1), iLinePointsBuffer(0), iLinePointsBufferCapacity(0), iLastDrawColor(0xFFFFFFFF) {}
|
CRenderer::CRenderer() : iRenderer(0), iDirectScreen(0), iScreenGc(0), iWsSession(), iWsWindowGroup(), iWsWindowGroupID(0), iWsWindow(), iWsScreen(0), iWsEventStatus(), iWsEvent(), iShowFPS(EFalse), iFPS(0), iFont(0), iWorkBuffer1(0), iWorkBuffer2(0), iWorkBufferSize(0), iTempRenderBitmap(0), iTempRenderBitmapWidth(0), iTempRenderBitmapHeight(0), iLastColorR(-1), iLastColorG(-1), iLastColorB(-1), iLinePointsBuffer(0), iLinePointsBufferCapacity(0), iLastDrawColor(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
CRenderer::~CRenderer()
|
CRenderer::~CRenderer()
|
||||||
{
|
{
|
||||||
@@ -505,13 +504,9 @@ Uint32 NGAGE_ConvertColor(float r, float g, float b, float a, float color_scale)
|
|||||||
TFixed bf = Real2Fix(b);
|
TFixed bf = Real2Fix(b);
|
||||||
TFixed af = Real2Fix(a);
|
TFixed af = Real2Fix(a);
|
||||||
|
|
||||||
rf = FixMul(rf, scalef);
|
rf = SDL_clamp(FixMul(rf, scalef), 0, ff);
|
||||||
gf = FixMul(gf, scalef);
|
gf = SDL_clamp(FixMul(gf, scalef), 0, ff);
|
||||||
bf = FixMul(bf, scalef);
|
bf = SDL_clamp(FixMul(bf, scalef), 0, ff);
|
||||||
|
|
||||||
rf = SDL_clamp(rf, 0, ff);
|
|
||||||
gf = SDL_clamp(gf, 0, ff);
|
|
||||||
bf = SDL_clamp(bf, 0, ff);
|
|
||||||
af = SDL_clamp(af, 0, ff);
|
af = SDL_clamp(af, 0, ff);
|
||||||
|
|
||||||
rf = FixMul(rf, ff) >> 16;
|
rf = FixMul(rf, ff) >> 16;
|
||||||
@@ -539,25 +534,18 @@ bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rec
|
|||||||
|
|
||||||
SDL_FColor *c = &texture->color;
|
SDL_FColor *c = &texture->color;
|
||||||
|
|
||||||
// Fast path 1: No transformations needed; direct BitBlt.
|
// Get render scale once.
|
||||||
if (c->a == 1.f && c->r == 1.f && c->g == 1.f && c->b == 1.f) {
|
|
||||||
// Get render scale.
|
|
||||||
float sx;
|
float sx;
|
||||||
float sy;
|
float sy;
|
||||||
SDL_GetRenderScale(renderer, &sx, &sy);
|
SDL_GetRenderScale(renderer, &sx, &sy);
|
||||||
|
|
||||||
if (sx == 1.f && sy == 1.f) {
|
// Fast path 1: No transformations needed; direct BitBlt.
|
||||||
|
if (c->a == 1.f && c->r == 1.f && c->g == 1.f && c->b == 1.f && sx == 1.f && sy == 1.f) {
|
||||||
TRect aSource(TPoint(srcrect->x, srcrect->y), TSize(srcrect->w, srcrect->h));
|
TRect aSource(TPoint(srcrect->x, srcrect->y), TSize(srcrect->w, srcrect->h));
|
||||||
TPoint aDest(dstrect->x, dstrect->y);
|
TPoint aDest(dstrect->x, dstrect->y);
|
||||||
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Get render scale (moved here to avoid redundant call in fast path).
|
|
||||||
float sx;
|
|
||||||
float sy;
|
|
||||||
SDL_GetRenderScale(renderer, &sx, &sy);
|
|
||||||
|
|
||||||
// Slow path: Transformations needed.
|
// Slow path: Transformations needed.
|
||||||
int w = phdata->cachedWidth;
|
int w = phdata->cachedWidth;
|
||||||
@@ -577,7 +565,6 @@ bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rec
|
|||||||
}
|
}
|
||||||
|
|
||||||
dest = iWorkBuffer1;
|
dest = iWorkBuffer1;
|
||||||
bool useBuffer1 = true;
|
|
||||||
|
|
||||||
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
|
if (c->a != 1.f || c->r != 1.f || c->g != 1.f || c->b != 1.f) {
|
||||||
TFixed rf = Real2Fix(c->r);
|
TFixed rf = Real2Fix(c->r);
|
||||||
@@ -591,7 +578,7 @@ bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rec
|
|||||||
|
|
||||||
ApplyColorMod(dest, source, pitch, w, h, texture->color, iColorModLUT);
|
ApplyColorMod(dest, source, pitch, w, h, texture->color, iColorModLUT);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
dest = (dest == iWorkBuffer1) ? iWorkBuffer2 : iWorkBuffer1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sx != 1.f || sy != 1.f) {
|
if (sx != 1.f || sy != 1.f) {
|
||||||
@@ -600,10 +587,8 @@ bool CRenderer::Copy(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rec
|
|||||||
TFixed center_x = Int2Fix(w / 2);
|
TFixed center_x = Int2Fix(w / 2);
|
||||||
TFixed center_y = Int2Fix(h / 2);
|
TFixed center_y = Int2Fix(h / 2);
|
||||||
|
|
||||||
dest = useBuffer1 ? iWorkBuffer1 : iWorkBuffer2;
|
|
||||||
ApplyScale(dest, source, pitch, w, h, center_x, center_y, scale_x, scale_y);
|
ApplyScale(dest, source, pitch, w, h, center_x, center_y, scale_x, scale_y);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temp bitmap to avoid destroying source texture.
|
// Use temp bitmap to avoid destroying source texture.
|
||||||
@@ -637,14 +622,22 @@ bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE
|
|||||||
const bool isNoFlip = (!copydata->flip);
|
const bool isNoFlip = (!copydata->flip);
|
||||||
const bool isNoColorMod = (c->a == 1.f && c->r == 1.f && c->g == 1.f && c->b == 1.f);
|
const bool isNoColorMod = (c->a == 1.f && c->r == 1.f && c->g == 1.f && c->b == 1.f);
|
||||||
|
|
||||||
// Fast path 1: Check for cardinal rotation cache opportunity (0°, 90°, 180°, 270°).
|
// Fast path 1: No transformations needed; direct BitBlt.
|
||||||
if (isNoFlip && isIdentityScale && isNoColorMod && !isNoRotation) {
|
if (isNoFlip && isIdentityScale && isNoRotation && isNoColorMod) {
|
||||||
TInt angleIndex = -1;
|
TRect aSource(TPoint(copydata->srcrect.x, copydata->srcrect.y), TSize(copydata->srcrect.w, copydata->srcrect.h));
|
||||||
TFixed angle = copydata->angle;
|
TPoint aDest(copydata->dstrect.x, copydata->dstrect.y);
|
||||||
|
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Use pre-calculated angle constants for comparison.
|
// Fast path 2: Check for cardinal rotation cache opportunity (0°, 90°, 180°, 270°).
|
||||||
if (angle == kAngleZero) {
|
if (isNoFlip && isIdentityScale && isNoColorMod && !isNoRotation) {
|
||||||
angleIndex = 0;
|
TFixed angle = copydata->angle;
|
||||||
|
TInt angleIndex = -1;
|
||||||
|
|
||||||
|
// Check cardinal angles with tolerance - optimized for early exit.
|
||||||
|
if (SDL_abs(angle - kAngleZero) < kAngleTolerance) {
|
||||||
|
angleIndex = 0; // 0°
|
||||||
} else if (SDL_abs(angle - kAnglePi_2) < kAngleTolerance) {
|
} else if (SDL_abs(angle - kAnglePi_2) < kAngleTolerance) {
|
||||||
angleIndex = 1; // 90°
|
angleIndex = 1; // 90°
|
||||||
} else if (SDL_abs(angle - kAnglePi) < kAngleTolerance) {
|
} else if (SDL_abs(angle - kAnglePi) < kAngleTolerance) {
|
||||||
@@ -666,14 +659,6 @@ bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast path 2: No transformations needed; direct BitBlt.
|
|
||||||
if (isNoFlip && isIdentityScale && isNoRotation && isNoColorMod) {
|
|
||||||
TRect aSource(TPoint(copydata->srcrect.x, copydata->srcrect.y), TSize(copydata->srcrect.w, copydata->srcrect.h));
|
|
||||||
TPoint aDest(copydata->dstrect.x, copydata->dstrect.y);
|
|
||||||
iRenderer->Gc()->BitBlt(aDest, phdata->bitmap, aSource);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slow path: Transformations needed.
|
// Slow path: Transformations needed.
|
||||||
int w = phdata->cachedWidth;
|
int w = phdata->cachedWidth;
|
||||||
int h = phdata->cachedHeight;
|
int h = phdata->cachedHeight;
|
||||||
@@ -692,26 +677,23 @@ bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE
|
|||||||
}
|
}
|
||||||
|
|
||||||
dest = iWorkBuffer1;
|
dest = iWorkBuffer1;
|
||||||
bool useBuffer1 = true;
|
|
||||||
|
|
||||||
if (copydata->flip) {
|
if (copydata->flip) {
|
||||||
ApplyFlip(dest, source, pitch, w, h, copydata->flip);
|
ApplyFlip(dest, source, pitch, w, h, copydata->flip);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
dest = (dest == iWorkBuffer1) ? iWorkBuffer2 : iWorkBuffer1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isIdentityScale) {
|
if (!isIdentityScale) {
|
||||||
dest = useBuffer1 ? iWorkBuffer1 : iWorkBuffer2;
|
|
||||||
ApplyScale(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->scale_x, copydata->scale_y);
|
ApplyScale(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->scale_x, copydata->scale_y);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
dest = (dest == iWorkBuffer1) ? iWorkBuffer2 : iWorkBuffer1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copydata->angle) {
|
if (copydata->angle) {
|
||||||
dest = useBuffer1 ? iWorkBuffer1 : iWorkBuffer2;
|
|
||||||
ApplyRotation(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->angle);
|
ApplyRotation(dest, source, pitch, w, h, copydata->center.x, copydata->center.y, copydata->angle);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
dest = (dest == iWorkBuffer1) ? iWorkBuffer2 : iWorkBuffer1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNoColorMod) {
|
if (!isNoColorMod) {
|
||||||
@@ -724,10 +706,8 @@ bool CRenderer::CopyEx(SDL_Renderer *renderer, SDL_Texture *texture, const NGAGE
|
|||||||
BuildColorModLUT(rf, gf, bf);
|
BuildColorModLUT(rf, gf, bf);
|
||||||
}
|
}
|
||||||
|
|
||||||
dest = useBuffer1 ? iWorkBuffer1 : iWorkBuffer2;
|
|
||||||
ApplyColorMod(dest, source, pitch, w, h, texture->color, iColorModLUT);
|
ApplyColorMod(dest, source, pitch, w, h, texture->color, iColorModLUT);
|
||||||
source = dest;
|
source = dest;
|
||||||
useBuffer1 = !useBuffer1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use temp bitmap to avoid destroying source texture.
|
// Use temp bitmap to avoid destroying source texture.
|
||||||
@@ -799,10 +779,12 @@ void CRenderer::DrawLines(NGAGE_Vertex *aVerts, const TInt aCount)
|
|||||||
iLinePointsBuffer[i] = TPoint(aVerts[i].x, aVerts[i].y);
|
iLinePointsBuffer[i] = TPoint(aVerts[i].x, aVerts[i].y);
|
||||||
}
|
}
|
||||||
|
|
||||||
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
|
// Pack color once - all vertices use the same color in polyline.
|
||||||
((TUint8)aVerts->color.b << 16) |
|
Uint8 ca = aVerts->color.a;
|
||||||
((TUint8)aVerts->color.g << 8) |
|
Uint8 cr = aVerts->color.r;
|
||||||
(TUint8)aVerts->color.r);
|
Uint8 cg = aVerts->color.g;
|
||||||
|
Uint8 cb = aVerts->color.b;
|
||||||
|
TUint32 aColor = (ca << 24) | (cb << 16) | (cg << 8) | cr;
|
||||||
|
|
||||||
iRenderer->Gc()->SetPenColor(aColor);
|
iRenderer->Gc()->SetPenColor(aColor);
|
||||||
iRenderer->Gc()->DrawPolyLineNoEndPoint(iLinePointsBuffer, aCount);
|
iRenderer->Gc()->DrawPolyLineNoEndPoint(iLinePointsBuffer, aCount);
|
||||||
@@ -813,14 +795,15 @@ void CRenderer::DrawPoints(NGAGE_Vertex *aVerts, const TInt aCount)
|
|||||||
{
|
{
|
||||||
if (iRenderer && iRenderer->Gc()) {
|
if (iRenderer && iRenderer->Gc()) {
|
||||||
// Batch points by color to minimize SetPenColor calls.
|
// Batch points by color to minimize SetPenColor calls.
|
||||||
TUint32 currentColor = 0xFFFFFFFF; // Invalid initial color
|
TUint32 currentColor = 0;
|
||||||
bool colorSet = false;
|
bool colorSet = false;
|
||||||
|
|
||||||
for (TInt i = 0; i < aCount; i++, aVerts++) {
|
for (TInt i = 0; i < aCount; i++, aVerts++) {
|
||||||
TUint32 aColor = (((TUint8)aVerts->color.a << 24) |
|
Uint8 ca = aVerts->color.a;
|
||||||
((TUint8)aVerts->color.b << 16) |
|
Uint8 cr = aVerts->color.r;
|
||||||
((TUint8)aVerts->color.g << 8) |
|
Uint8 cg = aVerts->color.g;
|
||||||
(TUint8)aVerts->color.r);
|
Uint8 cb = aVerts->color.b;
|
||||||
|
TUint32 aColor = (ca << 24) | (cb << 16) | (cg << 8) | cr;
|
||||||
|
|
||||||
// Only set pen color when it changes.
|
// Only set pen color when it changes.
|
||||||
if (!colorSet || aColor != currentColor) {
|
if (!colorSet || aColor != currentColor) {
|
||||||
@@ -838,7 +821,7 @@ void CRenderer::FillRects(NGAGE_Vertex *aVerts, const TInt aCount)
|
|||||||
{
|
{
|
||||||
if (iRenderer && iRenderer->Gc()) {
|
if (iRenderer && iRenderer->Gc()) {
|
||||||
// Batch rectangles by color to minimize SetPenColor/SetBrushColor calls.
|
// Batch rectangles by color to minimize SetPenColor/SetBrushColor calls.
|
||||||
TUint32 currentColor = 0xFFFFFFFF; // Invalid initial color
|
TUint32 currentColor = 0;
|
||||||
bool colorSet = false;
|
bool colorSet = false;
|
||||||
|
|
||||||
// Process rectangles (each rect uses 2 vertices: position and size).
|
// Process rectangles (each rect uses 2 vertices: position and size).
|
||||||
@@ -847,10 +830,11 @@ void CRenderer::FillRects(NGAGE_Vertex *aVerts, const TInt aCount)
|
|||||||
TSize size(aVerts[i + 1].x, aVerts[i + 1].y);
|
TSize size(aVerts[i + 1].x, aVerts[i + 1].y);
|
||||||
TRect rect(pos, size);
|
TRect rect(pos, size);
|
||||||
|
|
||||||
TUint32 aColor = (((TUint8)aVerts[i].color.a << 24) |
|
Uint8 ca = aVerts[i].color.a;
|
||||||
((TUint8)aVerts[i].color.b << 16) |
|
Uint8 cr = aVerts[i].color.r;
|
||||||
((TUint8)aVerts[i].color.g << 8) |
|
Uint8 cg = aVerts[i].color.g;
|
||||||
(TUint8)aVerts[i].color.r);
|
Uint8 cb = aVerts[i].color.b;
|
||||||
|
TUint32 aColor = (ca << 24) | (cb << 16) | (cg << 8) | cr;
|
||||||
|
|
||||||
// Only set colors when they change.
|
// Only set colors when they change.
|
||||||
if (!colorSet || aColor != currentColor) {
|
if (!colorSet || aColor != currentColor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user