This commit is contained in:
1 parent
039dcaa381
commit
4072fea1cc
6 files changed
+1439
-50
No files matched your search
+313
-39
@@ -211,7 +211,8 @@ begin
|
||||
and Assigned(glTexParameteri)
|
||||
and Assigned(glTexImage2D)
|
||||
and Assigned(glGetIntegerv)
|
||||
and Assigned(glPixelStorei)) then
|
||||
and Assigned(glPixelStorei)
|
||||
and Assigned(CastleGLES.glGetError)) then
|
||||
raise Exception.Create('Texture backend initialization failed');
|
||||
gTextureBackendReady := True;
|
||||
except
|
||||
@@ -221,6 +222,50 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function DrainTextureGLErrors: string;
|
||||
var
|
||||
ErrorCode: CastleGLES.GLenum;
|
||||
begin
|
||||
Result := '';
|
||||
repeat
|
||||
ErrorCode := CastleGLES.glGetError();
|
||||
if ErrorCode <> CastleGLES.GL_NO_ERROR then
|
||||
begin
|
||||
if Result <> '' then Result := Result + ', ';
|
||||
Result := Result + '0x' + IntToHex(ErrorCode, 8);
|
||||
end;
|
||||
until ErrorCode = CastleGLES.GL_NO_ERROR;
|
||||
end;
|
||||
|
||||
|
||||
procedure RequireTextureNoGLError(const aOperation, aStage: string);
|
||||
var
|
||||
Errors: string;
|
||||
begin
|
||||
Errors := DrainTextureGLErrors;
|
||||
if Errors <> '' then
|
||||
begin
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
raise Exception.Create(Format('texture %s — current GLES error at %s: %s',
|
||||
[aOperation, aStage, Errors]));
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure RequireNoPreexistingTextureGLError(const aOperation: string);
|
||||
var
|
||||
Errors: string;
|
||||
begin
|
||||
Errors := DrainTextureGLErrors;
|
||||
if Errors <> '' then
|
||||
begin
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
raise Exception.Create(Format('texture %s — pre-existing GLES error(s): %s',
|
||||
[aOperation, Errors]));
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure KMRenderMobileBindTexture(aTexId: Cardinal);
|
||||
begin
|
||||
RequireTextureBackendReady;
|
||||
@@ -243,61 +288,203 @@ var
|
||||
alphaData: array of Byte;
|
||||
pixelCount, I: Cardinal;
|
||||
unpackAlignment: CastleGLES.GLint;
|
||||
restoreUnpackAlignment: Boolean;
|
||||
begin
|
||||
RequireTextureBackendReady;
|
||||
if (aTexture = 0) or (aWidth = 0) or (aHeight = 0)
|
||||
or not IsPowerOfTwo(aWidth) or not IsPowerOfTwo(aHeight)
|
||||
or (aData = nil) then
|
||||
raise Exception.Create('Invalid texture upload parameters');
|
||||
alignmentKnown, alignmentSetAttempted, bindAttempted: Boolean;
|
||||
operationUnverified: Boolean;
|
||||
finalizeErrors, finalizeEntryErrors: string;
|
||||
|
||||
if aMode = tfAlpha8 then
|
||||
procedure AddFinalizeError(const aStage, aMessage: string);
|
||||
begin
|
||||
pixelCount := Cardinal(aWidth) * Cardinal(aHeight);
|
||||
SetLength(alphaData, pixelCount);
|
||||
for I := 0 to pixelCount - 1 do
|
||||
alphaData[I] := Byte((PCardinal(aData)[I] shr 24) and $FF);
|
||||
if finalizeErrors <> '' then finalizeErrors := finalizeErrors + '; ';
|
||||
finalizeErrors := finalizeErrors + aStage + ': ' + aMessage;
|
||||
end;
|
||||
|
||||
CastleGLES.glGetIntegerv(CastleGLES.GL_UNPACK_ALIGNMENT, @unpackAlignment);
|
||||
restoreUnpackAlignment := unpackAlignment <> 1;
|
||||
if restoreUnpackAlignment then
|
||||
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, 1);
|
||||
try
|
||||
KMRenderMobileBindTexture(aTexture);
|
||||
procedure CollectFinalizePending(const aStage: string);
|
||||
var
|
||||
Errors: string;
|
||||
begin
|
||||
if not gTextureBackendReady then Exit;
|
||||
try
|
||||
case aMode of
|
||||
tfRGB5A1:
|
||||
Errors := DrainTextureGLErrors;
|
||||
if Errors <> '' then AddFinalizeError(aStage, Errors);
|
||||
except
|
||||
on E: Exception do AddFinalizeError(aStage, E.Message);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure FinalizeUpdate(aCheckPending: Boolean);
|
||||
begin
|
||||
finalizeEntryErrors := '';
|
||||
if aCheckPending and operationUnverified and gTextureBackendReady then
|
||||
try
|
||||
finalizeEntryErrors := DrainTextureGLErrors;
|
||||
if finalizeEntryErrors <> '' then
|
||||
AddFinalizeError('update/finalize-entry', finalizeEntryErrors);
|
||||
except
|
||||
on E: Exception do
|
||||
AddFinalizeError('update/finalize-entry', E.Message);
|
||||
end;
|
||||
|
||||
if bindAttempted then
|
||||
if gTextureBackendReady then
|
||||
try
|
||||
operationUnverified := True;
|
||||
KMRenderMobileBindTexture(0);
|
||||
RequireTextureNoGLError('update', 'unbind');
|
||||
operationUnverified := False;
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_RED);
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_GREEN);
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_BLUE);
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_ALPHA);
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGB5_A1, aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
|
||||
operationUnverified := False;
|
||||
AddFinalizeError('update/unbind', E.Message);
|
||||
CollectFinalizePending('update/unbind');
|
||||
end;
|
||||
tfRGBA8:
|
||||
end
|
||||
else
|
||||
AddFinalizeError('update/unbind', 'current texture context is unavailable');
|
||||
|
||||
if alignmentKnown and alignmentSetAttempted and (unpackAlignment <> 1) then
|
||||
if gTextureBackendReady then
|
||||
try
|
||||
operationUnverified := True;
|
||||
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, unpackAlignment);
|
||||
RequireTextureNoGLError('update', 'restore-unpack');
|
||||
operationUnverified := False;
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
operationUnverified := False;
|
||||
AddFinalizeError('update/restore-unpack', E.Message);
|
||||
CollectFinalizePending('update/restore-unpack');
|
||||
end;
|
||||
end
|
||||
else
|
||||
AddFinalizeError('update/restore-unpack', 'current texture context is unavailable');
|
||||
end;
|
||||
|
||||
begin
|
||||
try
|
||||
RequireTextureBackendReady;
|
||||
if (aTexture = 0) or (aWidth = 0) or (aHeight = 0)
|
||||
or not IsPowerOfTwo(aWidth) or not IsPowerOfTwo(aHeight)
|
||||
or (aData = nil) then
|
||||
raise Exception.Create('Invalid texture upload parameters');
|
||||
if not (aMode in [tfRGB5A1, tfRGBA8, tfAlpha8]) then
|
||||
raise Exception.Create('Unsupported texture upload format');
|
||||
|
||||
RequireNoPreexistingTextureGLError('update');
|
||||
if aMode = tfAlpha8 then
|
||||
begin
|
||||
pixelCount := Cardinal(aWidth) * Cardinal(aHeight);
|
||||
SetLength(alphaData, pixelCount);
|
||||
for I := 0 to pixelCount - 1 do
|
||||
alphaData[I] := Byte((PCardinal(aData)[I] shr 24) and $FF);
|
||||
end;
|
||||
|
||||
alignmentKnown := False;
|
||||
alignmentSetAttempted := False;
|
||||
bindAttempted := False;
|
||||
operationUnverified := False;
|
||||
finalizeErrors := '';
|
||||
try
|
||||
operationUnverified := True;
|
||||
CastleGLES.glGetIntegerv(CastleGLES.GL_UNPACK_ALIGNMENT, @unpackAlignment);
|
||||
RequireTextureNoGLError('update', 'glGetIntegerv');
|
||||
operationUnverified := False;
|
||||
alignmentKnown := True;
|
||||
|
||||
if unpackAlignment <> 1 then
|
||||
begin
|
||||
alignmentSetAttempted := True;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, 1);
|
||||
RequireTextureNoGLError('update', 'glPixelStorei(1)');
|
||||
operationUnverified := False;
|
||||
end;
|
||||
|
||||
bindAttempted := True;
|
||||
operationUnverified := True;
|
||||
KMRenderMobileBindTexture(aTexture);
|
||||
RequireTextureNoGLError('update', 'glBindTexture');
|
||||
operationUnverified := False;
|
||||
|
||||
case aMode of
|
||||
tfRGB5A1, tfRGBA8:
|
||||
begin
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_RED);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_R)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_GREEN);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_G)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_BLUE);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_B)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_ALPHA);
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGBA8, aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_A)');
|
||||
operationUnverified := False;
|
||||
if aMode = tfRGB5A1 then
|
||||
begin
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGB5_A1,
|
||||
aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
|
||||
RequireTextureNoGLError('update', 'glTexImage2D');
|
||||
operationUnverified := False;
|
||||
end
|
||||
else
|
||||
begin
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_RGBA8,
|
||||
aWidth, aHeight, 0, CastleGLES.GL_RGBA, CastleGLES.GL_UNSIGNED_BYTE, aData);
|
||||
RequireTextureNoGLError('update', 'glTexImage2D');
|
||||
operationUnverified := False;
|
||||
end;
|
||||
end;
|
||||
tfAlpha8:
|
||||
begin
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_R, CastleGLES.GL_ONE);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_R)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_G, CastleGLES.GL_ONE);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_G)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_B, CastleGLES.GL_ONE);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_B)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_SWIZZLE_A, CastleGLES.GL_RED);
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_R8, aWidth, aHeight, 0, CastleGLES.GL_RED, CastleGLES.GL_UNSIGNED_BYTE, @alphaData[0]);
|
||||
RequireTextureNoGLError('update', 'glTexParameteri(GL_TEXTURE_SWIZZLE_A)');
|
||||
operationUnverified := False;
|
||||
operationUnverified := True;
|
||||
CastleGLES.glTexImage2D(CastleGLES.GL_TEXTURE_2D, 0, CastleGLES.GL_R8,
|
||||
aWidth, aHeight, 0, CastleGLES.GL_RED, CastleGLES.GL_UNSIGNED_BYTE, @alphaData[0]);
|
||||
RequireTextureNoGLError('update', 'glTexImage2D');
|
||||
operationUnverified := False;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
KMRenderMobileBindTexture(0);
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
FinalizeUpdate(True);
|
||||
if finalizeErrors <> '' then
|
||||
E.Message := E.Message + '; secondary finalize failure(s): ' + finalizeErrors;
|
||||
raise;
|
||||
end;
|
||||
end;
|
||||
finally
|
||||
if restoreUnpackAlignment then
|
||||
CastleGLES.glPixelStorei(CastleGLES.GL_UNPACK_ALIGNMENT, unpackAlignment);
|
||||
|
||||
FinalizeUpdate(False);
|
||||
if finalizeErrors <> '' then
|
||||
raise Exception.Create('texture update failed: ' + finalizeErrors);
|
||||
except
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
raise;
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -314,23 +501,110 @@ end;
|
||||
function KMRenderMobileCreateTexture(aMinFilter, aMagFilter: TKMFilterType): Cardinal;
|
||||
var
|
||||
texture: CastleGLES.GLuint;
|
||||
cleanupErrors, cleanupEntryErrors, cleanupFailure: string;
|
||||
cleanupReady, cleanupFailed: Boolean;
|
||||
begin
|
||||
RequireTextureBackendReady;
|
||||
RequireNoPreexistingTextureGLError('create');
|
||||
texture := 0;
|
||||
CastleGLES.glGenTextures(1, @texture);
|
||||
if texture = 0 then
|
||||
raise Exception.Create('Texture generation failed');
|
||||
try
|
||||
CastleGLES.glGenTextures(1, @texture);
|
||||
RequireTextureNoGLError('create', 'glGenTextures');
|
||||
if texture = 0 then
|
||||
raise Exception.Create('Texture generation failed');
|
||||
KMRenderMobileBindTexture(Cardinal(texture));
|
||||
RequireTextureNoGLError('create', 'glBindTexture');
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MIN_FILTER, TextureFilter(aMinFilter));
|
||||
RequireTextureNoGLError('create', 'glTexParameteri(GL_TEXTURE_MIN_FILTER)');
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MAG_FILTER, TextureFilter(aMagFilter));
|
||||
RequireTextureNoGLError('create', 'glTexParameteri(GL_TEXTURE_MAG_FILTER)');
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_WRAP_S, CastleGLES.GL_CLAMP_TO_EDGE);
|
||||
RequireTextureNoGLError('create', 'glTexParameteri(GL_TEXTURE_WRAP_S)');
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_WRAP_T, CastleGLES.GL_CLAMP_TO_EDGE);
|
||||
RequireTextureNoGLError('create', 'glTexParameteri(GL_TEXTURE_WRAP_T)');
|
||||
CastleGLES.glTexParameteri(CastleGLES.GL_TEXTURE_2D, CastleGLES.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
RequireTextureNoGLError('create', 'glTexParameteri(GL_TEXTURE_MAX_LEVEL)');
|
||||
Result := Cardinal(texture);
|
||||
except
|
||||
KMRenderMobileDeleteTexture(Cardinal(texture));
|
||||
raise;
|
||||
on E: Exception do
|
||||
begin
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
try
|
||||
cleanupErrors := '';
|
||||
cleanupEntryErrors := '';
|
||||
cleanupFailure := '';
|
||||
cleanupFailed := False;
|
||||
if texture <> 0 then
|
||||
begin
|
||||
cleanupReady := False;
|
||||
try
|
||||
RequireTextureBackendReady;
|
||||
cleanupReady := True;
|
||||
except
|
||||
on CleanupE: Exception do
|
||||
begin
|
||||
cleanupFailed := True;
|
||||
cleanupFailure := 'cleanup unavailable: ' + CleanupE.Message;
|
||||
end;
|
||||
end;
|
||||
if cleanupReady then
|
||||
begin
|
||||
try
|
||||
cleanupEntryErrors := DrainTextureGLErrors;
|
||||
except
|
||||
on CleanupE: Exception do
|
||||
begin
|
||||
cleanupFailed := True;
|
||||
cleanupFailure := 'cleanup-entry drain failed: ' + CleanupE.Message;
|
||||
end;
|
||||
end;
|
||||
try
|
||||
KMRenderMobileDeleteTexture(Cardinal(texture));
|
||||
except
|
||||
on CleanupE: Exception do
|
||||
begin
|
||||
cleanupFailed := True;
|
||||
if cleanupFailure <> '' then cleanupFailure := cleanupFailure + '; ';
|
||||
cleanupFailure := cleanupFailure + 'glDeleteTextures failed: ' + CleanupE.Message;
|
||||
end;
|
||||
end;
|
||||
try
|
||||
cleanupErrors := DrainTextureGLErrors;
|
||||
if cleanupErrors <> '' then
|
||||
begin
|
||||
cleanupFailed := True;
|
||||
if cleanupFailure <> '' then cleanupFailure := cleanupFailure + '; ';
|
||||
cleanupFailure := cleanupFailure + 'glDeleteTextures GLES error(s): ' + cleanupErrors;
|
||||
end;
|
||||
except
|
||||
on CleanupE: Exception do
|
||||
begin
|
||||
cleanupFailed := True;
|
||||
if cleanupFailure <> '' then cleanupFailure := cleanupFailure + '; ';
|
||||
cleanupFailure := cleanupFailure + 'cleanup drain failed: ' + CleanupE.Message;
|
||||
end;
|
||||
end;
|
||||
if cleanupEntryErrors <> '' then
|
||||
begin
|
||||
if cleanupFailed then
|
||||
begin
|
||||
if cleanupFailure <> '' then cleanupFailure := cleanupFailure + '; ';
|
||||
cleanupFailure := cleanupFailure + 'cleanup-entry GLES error(s): ' + cleanupEntryErrors;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
if cleanupFailed then
|
||||
try
|
||||
E.Message := E.Message + '; texture create cleanup failed: ' + cleanupFailure;
|
||||
except
|
||||
end;
|
||||
except
|
||||
KMRenderMobileInvalidateTextureBindingCache;
|
||||
end;
|
||||
raise;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
Reference in new issue
Block a user