Skip to content

Commit

Permalink
Secretly create and bind linear views of sRGB storage textures;
Browse files Browse the repository at this point in the history
  • Loading branch information
bjornbytes committed Nov 1, 2023
1 parent a28d66e commit e9743a2
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/core/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ typedef enum {
typedef struct {
gpu_texture* source;
gpu_texture_type type;
bool linear;
uint32_t layerIndex;
uint32_t layerCount;
uint32_t levelIndex;
Expand Down
26 changes: 25 additions & 1 deletion src/core/gpu_vk.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ typedef struct {
bool swapchain;
bool colorspace;
bool depthResolve;
bool formatList;
} gpu_extensions;

// State
Expand Down Expand Up @@ -444,6 +445,10 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
default: texture->aspect = VK_IMAGE_ASPECT_COLOR_BIT; break;
}

if (info->srgb && (info->usage & GPU_TEXTURE_STORAGE)) {
flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
}

texture->layout = getNaturalLayout(info->usage, texture->aspect);
texture->layers = type == VK_IMAGE_TYPE_2D ? info->size[2] : 0;
texture->samples = info->samples;
Expand Down Expand Up @@ -485,6 +490,24 @@ bool gpu_texture_init(gpu_texture* texture, gpu_texture_info* info) {
(info->upload.generateMipmaps ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : 0)
};

VkFormat formats[2];
VkImageFormatListCreateInfo imageFormatList;
if ((flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && state.extensions.formatList) {
imageFormatList = (VkImageFormatListCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO,
.viewFormatCount = COUNTOF(formats),
.pViewFormats = formats
};

formats[0] = convertFormat(texture->format, texture->srgb);
formats[1] = convertFormat(texture->format, !texture->srgb);

if (formats[0] != formats[1]) {
imageFormatList.pNext = imageInfo.pNext;
imageInfo.pNext = &imageFormatList;
}
}

VK(vkCreateImage(state.device, &imageInfo, NULL, &texture->handle), "Could not create texture") return false;
nickname(texture->handle, VK_OBJECT_TYPE_IMAGE, info->label);

Expand Down Expand Up @@ -621,7 +644,7 @@ bool gpu_texture_init_view(gpu_texture* texture, gpu_texture_view_info* info) {
texture->samples = info->source->samples;
texture->layers = info->layerCount ? info->layerCount : (info->source->layers - info->layerIndex);
texture->format = info->source->format;
texture->srgb = info->source->srgb;
texture->srgb = !info->linear;
}

static const VkImageViewType types[] = {
Expand Down Expand Up @@ -1986,6 +2009,7 @@ bool gpu_init(gpu_config* config) {
{ "VK_KHR_portability_enumeration", true, &state.extensions.portability },
{ "VK_EXT_debug_utils", config->debug, &state.extensions.debug },
{ "VK_EXT_swapchain_colorspace", true, &state.extensions.colorspace },
{ "VK_KHR_image_format_list", true, &state.extensions.formatList },
{ "VK_KHR_surface", true, &state.extensions.surface },
#if defined(_WIN32)
{ "VK_KHR_win32_surface", true, &state.extensions.surfaceOS },
Expand Down
21 changes: 20 additions & 1 deletion src/modules/graphics/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ struct Texture {
Sync sync;
gpu_texture* gpu;
gpu_texture* renderView;
gpu_texture* linearView;
Material* material;
TextureInfo info;
};
Expand Down Expand Up @@ -2138,6 +2139,22 @@ Texture* lovrTextureCreate(const TextureInfo* info) {
}
}

// Make a linear view of sRGB textures for storage bindings, since most GPUs don't support sRGB
// storage textures
if (info->srgb && (info->usage & TEXTURE_STORAGE)) {
gpu_texture_view_info view = {
.source = texture->gpu,
.type = (gpu_texture_type) info->type,
.linear = true
};

texture->linearView = malloc(gpu_sizeof_texture());
lovrAssert(texture->linearView, "Out of memory");
lovrAssert(gpu_texture_init_view(texture->linearView, &view), "Failed to create texture view");
} else {
texture->linearView = texture->gpu;
}

// Sample-only textures are exempt from sync tracking to reduce overhead. Instead, they are
// manually synchronized with a single barrier after the upload stream.
if (info->usage == TEXTURE_SAMPLE) {
Expand Down Expand Up @@ -5852,14 +5869,16 @@ void lovrPassSendTexture(Pass* pass, const char* name, size_t length, uint32_t s

lovrCheck(shader->textureMask & (1u << slot), "Trying to send a Texture to slot %d, but the active Shader doesn't have a Texture in that slot");

gpu_texture* view = texture->gpu;
if (shader->storageMask & (1u << slot)) {
lovrCheck(texture->info.usage & TEXTURE_STORAGE, "Textures must be created with the 'storage' usage to send them to image variables in shaders");
view = texture->linearView;
} else {
lovrCheck(texture->info.usage & TEXTURE_SAMPLE, "Textures must be created with the 'sample' usage to send them to sampler variables in shaders");
}

trackTexture(pass, texture, resource->phase, resource->cache);
pass->bindings[slot].texture = texture->gpu;
pass->bindings[slot].texture = view;
pass->bindingMask |= (1u << slot);
pass->flags |= DIRTY_BINDINGS;
}
Expand Down

0 comments on commit e9743a2

Please sign in to comment.