Skip to content

Commit

Permalink
MODERN: Error handling for texture arrays
Browse files Browse the repository at this point in the history
NVIDIA driver was returning 2 errors in 32-bit
Splits 3d-sprite arrays by size
Error detection moved back to the texture array
  logic, as we need to reduce size in way that
  won't break lumas
  • Loading branch information
meag committed Feb 12, 2021
1 parent 0f3418c commit 63acd28
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 100 deletions.
33 changes: 14 additions & 19 deletions gl_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,37 +234,32 @@ void GL_AllocateStorage(gltexture_t* texture)
}

#ifdef RENDERER_OPTION_MODERN_OPENGL
qbool GLM_TextureAllocateArrayStorage(gltexture_t* slot, int minimum_depth, int* depth)
qbool GLM_TextureAllocateArrayStorage(gltexture_t* slot)
{
GLenum error;

while (*depth >= minimum_depth) {
R_TraceAPI("Allocating %d x %d x %d, %d miplevels\n", slot->texture_width, slot->texture_height, *depth, slot->miplevels);
error = GL_TexStorage3D(GL_TEXTURE0, slot->reference, slot->miplevels, GL_StorageFormat(TEX_ALPHA), slot->texture_width, slot->texture_height, *depth, false);
R_TraceAPI("Allocating %d x %d x %d, %d miplevels\n", slot->texture_width, slot->texture_height, slot->depth, slot->miplevels);
GL_ProcessErrors("GLM_TextureAllocateArrayStorage flush");
error = GL_TexStorage3D(GL_TEXTURE0, slot->reference, slot->miplevels, GL_StorageFormat(TEX_ALPHA), slot->texture_width, slot->texture_height, slot->depth, false);

if (error == GL_OUT_OF_MEMORY && *depth > 2) {
*depth /= 2;
R_TraceAPI("!!ERROR Array allocation failed (memory), reducing size to %d...\n", *depth);
continue;
}
else if (error != GL_NO_ERROR) {
if (error != GL_NO_ERROR) {
#ifdef WITH_RENDERING_TRACE
int array_width, array_height, array_depth;
array_width = R_TextureWidth(slot->reference);
array_height = R_TextureHeight(slot->reference);
array_depth = R_TextureDepth(slot->reference);
int array_width, array_height, array_depth;

array_width = R_TextureWidth(slot->reference);
array_height = R_TextureHeight(slot->reference);
array_depth = R_TextureDepth(slot->reference);

R_TraceAPI("!!ERROR Array allocation failed, error %X: [mip %d, %d x %d x %d]\n", error, slot->miplevels, slot->texture_width, slot->texture_height, *depth);
R_TraceAPI(" > Sizes reported: %d x %d x %d\n", array_width, array_height, array_depth);
R_TraceAPI("!!ERROR Array allocation failed, error %X: [mip %d, %d x %d x %d]\n", error, slot->miplevels, slot->texture_width, slot->texture_height, slot->depth);
R_TraceAPI(" > Sizes reported: %d x %d x %d\n", array_width, array_height, array_depth);
#endif
return false;
}
break;
return false;
}

#ifdef DEBUG_MEMORY_ALLOCATIONS
Sys_Printf("\nopengl-texture,alloc,%u,%d,%d,%d,%s\n", slot->reference.index, slot->texture_width, slot->texture_height, slot->texture_width * slot->texture_height * slot->depth * (slot->texmode & TEX_ALPHA ? 4 : 3), slot->identifier);
#endif

return true;
}
#endif // RENDERER_OPTION_MODERN_OPENGL
Expand Down
2 changes: 1 addition & 1 deletion gl_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ void GL_UploadTexture(texture_ref texture, int mode, int width, int height, byte
void GL_ReplaceSubImageRGBA(texture_ref ref, int offsetx, int offsety, int width, int height, byte* buffer);

// Internal
qbool GLM_TextureAllocateArrayStorage(gltexture_t* slot, int minimum_depth, int* depth);
qbool GLM_TextureAllocateArrayStorage(gltexture_t* slot);
void GL_AllocateStorage(gltexture_t* texture);
void GL_AllocateTextureNames(gltexture_t* glt);

Expand Down
172 changes: 102 additions & 70 deletions glm_texture_arrays.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,102 @@ static void GL_ImportTexturesForModel(model_t* mod)
}
}

static int GLM_FindPotentialSizes(int i, int* potential_sizes, int flagged_type, qbool maximise, int* req_width, int* req_height)
{
int size_index = 0;
int j;
int width = R_TextureWidth(texture_flags[i].ref);
int height = R_TextureHeight(texture_flags[i].ref);

potential_sizes[size_index++] = 1 + texture_flags[i].subsequent;

// Count how many textures of the same size we have
for (j = i + 1; j < MAX_GLTEXTURES; ++j) {
if (!(texture_flags[j].flags & (1 << flagged_type))) {
break;
}

if (maximise) {
width = max(width, R_TextureWidth(texture_flags[j].ref));
height = max(height, R_TextureHeight(texture_flags[j].ref));
}
else if (R_TextureWidth(texture_flags[j].ref) != width || R_TextureHeight(texture_flags[j].ref) != height) {
break;
}

potential_sizes[size_index] = potential_sizes[size_index - 1] + 1 + texture_flags[j].subsequent;
++size_index;
}

*req_width = width;
*req_height = height;
return size_index;
}

static void GLM_CopyTexturesToArray(texture_ref array_ref, int flagged_type, int min_index, int max_index, int width, int height)
{
int array_index = 0;
int k;

// texture created ok
if (flagged_type == TEXTURETYPES_SPRITES) {
renderer.TextureWrapModeClamp(array_ref);
}

// Copy the 2D textures across
for (k = min_index; k <= max_index; ++k) {
texture_ref ref_2d = texture_flags[k].ref;

// TODO: compression: flag as ANYSIZE and set scale_s/scale_t accordingly
GL_AddTextureToArray(array_ref, array_index, ref_2d, false);
texture_flags[k].array_ref[flagged_type].ref = array_ref;
texture_flags[k].array_ref[flagged_type].index = array_index;
texture_flags[k].array_ref[flagged_type].scale_s = (R_TextureWidth(ref_2d) * 1.0f) / width;
texture_flags[k].array_ref[flagged_type].scale_t = (R_TextureHeight(ref_2d) * 1.0f) / height;

// (subsequent are the luma textures on brush models)
array_index += 1 + texture_flags[k].subsequent;
}
}

static int GLM_CreateArrayFromPotentialSizes(int i, int* potential_sizes, int size_index_max, qbool return_on_failure, int width, int height)
{
int size_attempt, depth;

const char* textureTypeNames[] = {
"aliasmodel",
"brushmodel",
"worldmodel",
"sprites",
};

for (size_attempt = size_index_max - 1; size_attempt >= 0; --size_attempt) {
// create array of desired size
char name[64];
texture_ref array_ref;

R_TextureReferenceInvalidate(array_ref);
depth = potential_sizes[size_attempt];
snprintf(name, sizeof(name), "%s_%d[%dx%dx%d]", textureTypeNames[flagged_type], i, width, height, depth);

array_ref = R_CreateTextureArray(name, width, height, depth, TEX_MIPMAP | TEX_ALPHA);
if (R_TextureReferenceIsValid(array_ref)) {
GLM_CopyTexturesToArray(array_ref, flagged_type, i, i + size_attempt, width, height);
return size_attempt;
}
}

if (!return_on_failure) {
Sys_Error("Failed to create array size %dx%dx%d\n", width, height, potential_sizes[size_index_max - 1]);
}
return -1;
}

// Called from R_NewMap
void GLM_BuildCommonTextureArrays(qbool vid_restart)
{
int i;
int potential_sizes[MAX_GLTEXTURES];

GL_DeleteExistingTextureArrays(!vid_restart);
R_ClearModelTextureData();
Expand Down Expand Up @@ -491,82 +583,22 @@ void GLM_BuildCommonTextureArrays(qbool vid_restart)
qsort(texture_flags, MAX_GLTEXTURES, sizeof(texture_flags[0]), SortFlaggedTextures);

for (i = 0; i < MAX_GLTEXTURES; ++i) {
int same_size = 0;
int width, height;
int j;
int depth;
int size_index_max = 0;
int extra_slots_added;
int req_width, req_height;

if (!(texture_flags[i].flags & (1 << flagged_type))) {
continue;
}

width = R_TextureWidth(texture_flags[i].ref);
height = R_TextureHeight(texture_flags[i].ref);
same_size = 1 + texture_flags[i].subsequent;

// Count how many textures of the same size we have
for (j = i + 1; j < MAX_GLTEXTURES; ++j) {
if (!(texture_flags[j].flags & (1 << flagged_type))) {
break;
}

if (flagged_type == TEXTURETYPES_SPRITES) {
width = max(width, R_TextureWidth(texture_flags[j].ref));
height = max(height, R_TextureHeight(texture_flags[j].ref));
}
else if (R_TextureWidth(texture_flags[j].ref) != width || R_TextureHeight(texture_flags[j].ref) != height) {
break;
}

same_size += 1 + texture_flags[j].subsequent;
}

// Create an array of that size
while (same_size > 0) {
texture_ref array_ref;
int index = 0;
int k;
char name[64];
const char* textureTypeNames[] = {
"aliasmodel",
"brushmodel",
"worldmodel",
"sprites",
};

snprintf(name, sizeof(name), "%s[%dx%dx%d]", textureTypeNames[flagged_type], width, height, same_size);

depth = same_size;
array_ref = R_CreateTextureArray(name, width, height, &depth, TEX_MIPMAP | TEX_ALPHA, 1);
if (!R_TextureReferenceIsValid(array_ref)) {
Sys_Error("Failed to create array size %dx%dx%d\n", width, height, depth);
}

if (flagged_type == TEXTURETYPES_SPRITES) {
renderer.TextureWrapModeClamp(array_ref);
}

// Copy the 2D textures across
for (k = i; k < j; ++k) {
texture_ref ref_2d = texture_flags[k].ref;

// TODO: compression: flag as ANYSIZE and set scale_s/scale_t accordingly
GL_AddTextureToArray(array_ref, index, ref_2d, false);
texture_flags[k].array_ref[flagged_type].ref = array_ref;
texture_flags[k].array_ref[flagged_type].index = index++;
texture_flags[k].array_ref[flagged_type].scale_s = (R_TextureWidth(ref_2d) * 1.0f) / width;
texture_flags[k].array_ref[flagged_type].scale_t = (R_TextureHeight(ref_2d) * 1.0f) / height;

// Skip these and fill them in later
index += texture_flags[k].subsequent;
}

//R_GenerateMipmapsIfNeeded(array_ref);
same_size -= depth;
i = j;
size_index_max = GLM_FindPotentialSizes(i, potential_sizes, flagged_type, flagged_type == TEXTURETYPES_SPRITES, &req_width, &req_height);
extra_slots_added = GLM_CreateArrayFromPotentialSizes(i, potential_sizes, size_index_max, flagged_type == TEXTURETYPES_SPRITES, req_width, req_height);
if (extra_slots_added == -1) {
// try again without maximising
GLM_FindPotentialSizes(i, potential_sizes, flagged_type, false, &req_width, &req_height);
extra_slots_added = GLM_CreateArrayFromPotentialSizes(i, potential_sizes, size_index_max, false, req_width, req_height);
}

i--;
i += extra_slots_added;
}
}

Expand Down
20 changes: 11 additions & 9 deletions r_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,12 +492,13 @@ void R_SetTextureArraySize(texture_ref tex, int width, int height, int depth, in

// We could flag the textures as they're created and then move all 2d>3d to this module?
// FIXME: Ensure not called in immediate-mode OpenGL
texture_ref R_CreateTextureArray(const char* identifier, int width, int height, int* depth, int mode, int minimum_depth)
texture_ref R_CreateTextureArray(const char* identifier, int width, int height, int depth, int mode)
{
qbool new_texture = false;
gltexture_t* slot = R_TextureAllocateSlot(texture_type_2d_array, identifier, width, height, *depth, 4, mode | TEX_NOSCALE, 0, &new_texture);
gltexture_t* slot;
texture_ref gl_texturenum;

slot = R_TextureAllocateSlot(texture_type_2d_array, identifier, width, height, depth, 4, mode | TEX_NOSCALE, 0, &new_texture);
if (!slot) {
return invalid_texture_reference;
}
Expand All @@ -510,15 +511,16 @@ texture_ref R_CreateTextureArray(const char* identifier, int width, int height,

#ifdef RENDERER_OPTION_MODERN_OPENGL
if (R_UseModernOpenGL()) {
renderer.TextureUnitBind(0, gl_texturenum);
if (GLM_TextureAllocateArrayStorage(slot, minimum_depth, depth)) {
texture_ref tex = slot->reference;

renderer.TextureUnitBind(0, tex);
if (GLM_TextureAllocateArrayStorage(slot)) {
R_TextureUtil_SetFiltering(slot->reference);
return tex;
}
else {
texture_ref tex = slot->reference;
R_DeleteTexture(&tex);
return null_texture_reference;
}

R_DeleteTexture(&tex);
return null_texture_reference;
}
#endif
#ifdef RENDERER_OPTION_VULKAN
Expand Down
2 changes: 1 addition & 1 deletion r_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ texture_ref R_LoadTexture(const char *identifier, int width, int height, byte *d
texture_ref R_LoadPicTexture(const char *name, mpic_t *pic, byte *data);
texture_ref R_LoadTexturePixels(byte *data, const char *identifier, int width, int height, int mode);
texture_ref R_LoadTextureImage(const char *filename, const char *identifier, int matchwidth, int matchheight, int mode);
texture_ref R_CreateTextureArray(const char* identifier, int width, int height, int* depth, int mode, int minimum_depth);
texture_ref R_CreateTextureArray(const char* identifier, int width, int height, int depth, int mode);
texture_ref R_CreateCubeMap(const char* identifier, int width, int height, int mode);
void R_DeleteTextureArray(texture_ref* texture);
void R_DeleteCubeMap(texture_ref* texture);
Expand Down

0 comments on commit 63acd28

Please sign in to comment.