Fix Vulkan texture drawing.
This commit is contained in:
parent
af7fc20c38
commit
4e27539709
|
@ -164,33 +164,37 @@ void SpirvShaderTranslator::StartTranslation() {
|
||||||
push_constants_type, "push_consts");
|
push_constants_type, "push_consts");
|
||||||
|
|
||||||
// Texture bindings
|
// Texture bindings
|
||||||
Id samplers_t = b.makeSamplerType();
|
Id tex_t[] = {b.makeSampledImageType(b.makeImageType(
|
||||||
Id img_t[] = {
|
float_type_, spv::Dim::Dim1D, false, false, false, 1,
|
||||||
b.makeImageType(float_type_, spv::Dim::Dim1D, false, false, false, 1,
|
spv::ImageFormat::ImageFormatUnknown)),
|
||||||
spv::ImageFormat::ImageFormatUnknown),
|
b.makeSampledImageType(b.makeImageType(
|
||||||
b.makeImageType(float_type_, spv::Dim::Dim2D, false, false, false, 1,
|
float_type_, spv::Dim::Dim2D, false, false, false, 1,
|
||||||
spv::ImageFormat::ImageFormatUnknown),
|
spv::ImageFormat::ImageFormatUnknown)),
|
||||||
b.makeImageType(float_type_, spv::Dim::Dim3D, false, false, false, 1,
|
b.makeSampledImageType(b.makeImageType(
|
||||||
spv::ImageFormat::ImageFormatUnknown),
|
float_type_, spv::Dim::Dim3D, false, false, false, 1,
|
||||||
b.makeImageType(float_type_, spv::Dim::DimCube, false, false, false, 1,
|
spv::ImageFormat::ImageFormatUnknown)),
|
||||||
spv::ImageFormat::ImageFormatUnknown)};
|
b.makeSampledImageType(b.makeImageType(
|
||||||
|
float_type_, spv::Dim::DimCube, false, false, false, 1,
|
||||||
|
spv::ImageFormat::ImageFormatUnknown))};
|
||||||
|
|
||||||
Id samplers_a = b.makeArrayType(samplers_t, b.makeUintConstant(32), 0);
|
// Id samplers_a = b.makeArrayType(sampler_t, b.makeUintConstant(32), 0);
|
||||||
Id img_a_t[] = {b.makeArrayType(img_t[0], b.makeUintConstant(32), 0),
|
Id tex_a_t[] = {b.makeArrayType(tex_t[0], b.makeUintConstant(32), 0),
|
||||||
b.makeArrayType(img_t[1], b.makeUintConstant(32), 0),
|
b.makeArrayType(tex_t[1], b.makeUintConstant(32), 0),
|
||||||
b.makeArrayType(img_t[2], b.makeUintConstant(32), 0),
|
b.makeArrayType(tex_t[2], b.makeUintConstant(32), 0),
|
||||||
b.makeArrayType(img_t[3], b.makeUintConstant(32), 0)};
|
b.makeArrayType(tex_t[3], b.makeUintConstant(32), 0)};
|
||||||
|
|
||||||
samplers_ = b.createVariable(spv::StorageClass::StorageClassUniformConstant,
|
// TODO(DrChat): See texture_cache.cc - do we need separate samplers here?
|
||||||
samplers_a, "samplers");
|
// samplers_ =
|
||||||
b.addDecoration(samplers_, spv::Decoration::DecorationDescriptorSet, 1);
|
// b.createVariable(spv::StorageClass::StorageClassUniformConstant,
|
||||||
b.addDecoration(samplers_, spv::Decoration::DecorationBinding, 0);
|
// samplers_a, "samplers");
|
||||||
|
// b.addDecoration(samplers_, spv::Decoration::DecorationDescriptorSet, 1);
|
||||||
|
// b.addDecoration(samplers_, spv::Decoration::DecorationBinding, 0);
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
img_[i] = b.createVariable(spv::StorageClass::StorageClassUniformConstant,
|
tex_[i] = b.createVariable(spv::StorageClass::StorageClassUniformConstant,
|
||||||
img_a_t[i],
|
tex_a_t[i],
|
||||||
xe::format_string("images%dD", i + 1).c_str());
|
xe::format_string("textures%dD", i + 1).c_str());
|
||||||
b.addDecoration(img_[i], spv::Decoration::DecorationDescriptorSet, 1);
|
b.addDecoration(tex_[i], spv::Decoration::DecorationDescriptorSet, 1);
|
||||||
b.addDecoration(img_[i], spv::Decoration::DecorationBinding, i + 1);
|
b.addDecoration(tex_[i], spv::Decoration::DecorationBinding, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolators.
|
// Interpolators.
|
||||||
|
@ -674,25 +678,15 @@ void SpirvShaderTranslator::ProcessTextureFetchInstruction(
|
||||||
|
|
||||||
switch (instr.opcode) {
|
switch (instr.opcode) {
|
||||||
case FetchOpcode::kTextureFetch: {
|
case FetchOpcode::kTextureFetch: {
|
||||||
auto image_index = b.makeUintConstant(instr.operands[1].storage_index);
|
auto texture_index = b.makeUintConstant(instr.operands[1].storage_index);
|
||||||
auto image_ptr =
|
auto texture_ptr =
|
||||||
b.createAccessChain(spv::StorageClass::StorageClassUniformConstant,
|
b.createAccessChain(spv::StorageClass::StorageClassUniformConstant,
|
||||||
img_[dim_idx], std::vector<Id>({image_index}));
|
tex_[dim_idx], std::vector<Id>({texture_index}));
|
||||||
auto sampler_ptr =
|
auto texture = b.createLoad(texture_ptr);
|
||||||
b.createAccessChain(spv::StorageClass::StorageClassUniformConstant,
|
|
||||||
samplers_, std::vector<Id>({image_index}));
|
|
||||||
auto image = b.createLoad(image_ptr);
|
|
||||||
auto sampler = b.createLoad(sampler_ptr);
|
|
||||||
assert(b.isImageType(b.getTypeId(image)));
|
|
||||||
assert(b.isSamplerType(b.getTypeId(sampler)));
|
|
||||||
|
|
||||||
auto sampled_image_type = b.makeSampledImageType(b.getImageType(image));
|
|
||||||
auto tex = b.createBinOp(spv::Op::OpSampledImage, sampled_image_type,
|
|
||||||
image, sampler);
|
|
||||||
|
|
||||||
spv::Builder::TextureParameters params = {0};
|
spv::Builder::TextureParameters params = {0};
|
||||||
params.coords = src;
|
params.coords = src;
|
||||||
params.sampler = tex;
|
params.sampler = texture;
|
||||||
dest = b.createTextureCall(spv::NoPrecision, vec4_float_type_, false,
|
dest = b.createTextureCall(spv::NoPrecision, vec4_float_type_, false,
|
||||||
false, false, false, false, params);
|
false, false, false, false, params);
|
||||||
} break;
|
} break;
|
||||||
|
@ -1741,10 +1735,18 @@ void SpirvShaderTranslator::StoreToResult(Id source_value_id,
|
||||||
auto n_dst = b.getNumTypeComponents(storage_type);
|
auto n_dst = b.getNumTypeComponents(storage_type);
|
||||||
assert_true(n_el < n_dst);
|
assert_true(n_el < n_dst);
|
||||||
|
|
||||||
constituents.push_back(source_value_id);
|
if (n_el == 1) {
|
||||||
for (int i = n_el; i < n_dst; i++) {
|
// Smear scalar.
|
||||||
// Pad with zeroes.
|
for (int i = 0; i < n_dst; i++) {
|
||||||
constituents.push_back(b.makeFloatConstant(0.f));
|
constituents.push_back(source_value_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME: This may not work as intended.
|
||||||
|
constituents.push_back(source_value_id);
|
||||||
|
for (int i = n_el; i < n_dst; i++) {
|
||||||
|
// Pad with zeroes.
|
||||||
|
constituents.push_back(b.makeFloatConstant(0.f));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
source_value_id =
|
source_value_id =
|
||||||
|
|
|
@ -122,7 +122,7 @@ class SpirvShaderTranslator : public ShaderTranslator {
|
||||||
spv::Id interpolators_ = 0;
|
spv::Id interpolators_ = 0;
|
||||||
spv::Id frag_outputs_ = 0;
|
spv::Id frag_outputs_ = 0;
|
||||||
spv::Id samplers_ = 0;
|
spv::Id samplers_ = 0;
|
||||||
spv::Id img_[4] = {0}; // Images {1D, 2D, 3D, Cube}
|
spv::Id tex_[4] = {0}; // Images {1D, 2D, 3D, Cube}
|
||||||
|
|
||||||
// Map of {binding -> {offset -> spv input}}
|
// Map of {binding -> {offset -> spv input}}
|
||||||
std::map<uint32_t, std::map<uint32_t, spv::Id>> vertex_binding_map_;
|
std::map<uint32_t, std::map<uint32_t, spv::Id>> vertex_binding_map_;
|
||||||
|
|
|
@ -42,7 +42,7 @@ TextureCache::TextureCache(RegisterFile* register_file,
|
||||||
VkDescriptorPoolSize pool_sizes[2];
|
VkDescriptorPoolSize pool_sizes[2];
|
||||||
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
pool_sizes[0].descriptorCount = 32;
|
pool_sizes[0].descriptorCount = 32;
|
||||||
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
pool_sizes[1].descriptorCount = 32;
|
pool_sizes[1].descriptorCount = 32;
|
||||||
descriptor_pool_info.poolSizeCount = 2;
|
descriptor_pool_info.poolSizeCount = 2;
|
||||||
descriptor_pool_info.pPoolSizes = pool_sizes;
|
descriptor_pool_info.pPoolSizes = pool_sizes;
|
||||||
|
@ -63,7 +63,7 @@ TextureCache::TextureCache(RegisterFile* register_file,
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
auto& texture_binding = bindings[1 + i];
|
auto& texture_binding = bindings[1 + i];
|
||||||
texture_binding.binding = 1 + i;
|
texture_binding.binding = 1 + i;
|
||||||
texture_binding.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
texture_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
texture_binding.descriptorCount = kMaxTextureSamplers;
|
texture_binding.descriptorCount = kMaxTextureSamplers;
|
||||||
texture_binding.stageFlags =
|
texture_binding.stageFlags =
|
||||||
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
@ -94,35 +94,37 @@ TextureCache::TextureCache(RegisterFile* register_file,
|
||||||
err =
|
err =
|
||||||
vkCreateBuffer(*device_, &staging_buffer_info, nullptr, &staging_buffer_);
|
vkCreateBuffer(*device_, &staging_buffer_info, nullptr, &staging_buffer_);
|
||||||
CheckResult(err, "vkCreateBuffer");
|
CheckResult(err, "vkCreateBuffer");
|
||||||
|
if (err != VK_SUCCESS) {
|
||||||
if (err == VK_SUCCESS) {
|
// This isn't good.
|
||||||
VkMemoryRequirements staging_buffer_reqs;
|
assert_always();
|
||||||
vkGetBufferMemoryRequirements(*device_, staging_buffer_,
|
return;
|
||||||
&staging_buffer_reqs);
|
|
||||||
staging_buffer_mem_ = device_->AllocateMemory(staging_buffer_reqs);
|
|
||||||
assert_not_null(staging_buffer_mem_);
|
|
||||||
|
|
||||||
err = vkBindBufferMemory(*device_, staging_buffer_, staging_buffer_mem_, 0);
|
|
||||||
CheckResult(err, "vkBindBufferMemory");
|
|
||||||
|
|
||||||
// Upload a grid into the staging buffer.
|
|
||||||
uint32_t* gpu_data = nullptr;
|
|
||||||
err =
|
|
||||||
vkMapMemory(*device_, staging_buffer_mem_, 0, staging_buffer_info.size,
|
|
||||||
0, reinterpret_cast<void**>(&gpu_data));
|
|
||||||
CheckResult(err, "vkMapMemory");
|
|
||||||
|
|
||||||
int width = 2048;
|
|
||||||
int height = 2048;
|
|
||||||
for (int y = 0; y < height; ++y) {
|
|
||||||
for (int x = 0; x < width; ++x) {
|
|
||||||
gpu_data[y * width + x] =
|
|
||||||
((y % 32 < 16) ^ (x % 32 >= 16)) ? 0xFF0000FF : 0xFFFFFFFF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vkUnmapMemory(*device_, staging_buffer_mem_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements staging_buffer_reqs;
|
||||||
|
vkGetBufferMemoryRequirements(*device_, staging_buffer_,
|
||||||
|
&staging_buffer_reqs);
|
||||||
|
staging_buffer_mem_ = device_->AllocateMemory(staging_buffer_reqs);
|
||||||
|
assert_not_null(staging_buffer_mem_);
|
||||||
|
|
||||||
|
err = vkBindBufferMemory(*device_, staging_buffer_, staging_buffer_mem_, 0);
|
||||||
|
CheckResult(err, "vkBindBufferMemory");
|
||||||
|
|
||||||
|
// Upload a grid into the staging buffer.
|
||||||
|
uint32_t* gpu_data = nullptr;
|
||||||
|
err = vkMapMemory(*device_, staging_buffer_mem_, 0, staging_buffer_info.size,
|
||||||
|
0, reinterpret_cast<void**>(&gpu_data));
|
||||||
|
CheckResult(err, "vkMapMemory");
|
||||||
|
|
||||||
|
int width = 2048;
|
||||||
|
int height = 2048;
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
gpu_data[y * width + x] =
|
||||||
|
((y % 32 < 16) ^ (x % 32 >= 16)) ? 0xFF0000FF : 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vkUnmapMemory(*device_, staging_buffer_mem_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::~TextureCache() {
|
TextureCache::~TextureCache() {
|
||||||
|
@ -131,9 +133,141 @@ TextureCache::~TextureCache() {
|
||||||
vkDestroyDescriptorPool(*device_, descriptor_pool_, nullptr);
|
vkDestroyDescriptorPool(*device_, descriptor_pool_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureCache::Texture* TextureCache::AllocateTexture(
|
||||||
|
const TextureInfo& texture_info) {
|
||||||
|
// Create an image first.
|
||||||
|
VkImageCreateInfo image_info = {};
|
||||||
|
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
switch (texture_info.dimension) {
|
||||||
|
case Dimension::k1D:
|
||||||
|
image_info.imageType = VK_IMAGE_TYPE_1D;
|
||||||
|
break;
|
||||||
|
case Dimension::k2D:
|
||||||
|
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
break;
|
||||||
|
case Dimension::k3D:
|
||||||
|
image_info.imageType = VK_IMAGE_TYPE_3D;
|
||||||
|
break;
|
||||||
|
case Dimension::kCube:
|
||||||
|
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(texture_info.dimension);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Format
|
||||||
|
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
image_info.extent = {texture_info.width + 1, texture_info.height + 1,
|
||||||
|
texture_info.depth + 1};
|
||||||
|
image_info.mipLevels = 1;
|
||||||
|
image_info.arrayLayers = 1;
|
||||||
|
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
|
||||||
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
image_info.queueFamilyIndexCount = 0;
|
||||||
|
image_info.pQueueFamilyIndices = nullptr;
|
||||||
|
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
VkImage image;
|
||||||
|
auto err = vkCreateImage(*device_, &image_info, nullptr, &image);
|
||||||
|
CheckResult(err, "vkCreateImage");
|
||||||
|
|
||||||
|
VkMemoryRequirements mem_requirements;
|
||||||
|
vkGetImageMemoryRequirements(*device_, image, &mem_requirements);
|
||||||
|
|
||||||
|
// TODO: Use a circular buffer or something else to allocate this memory.
|
||||||
|
// The device has a limited amount (around 64) of memory allocations that we
|
||||||
|
// can make.
|
||||||
|
// Now that we have the size, back the image with GPU memory.
|
||||||
|
auto memory = device_->AllocateMemory(mem_requirements, 0);
|
||||||
|
if (!memory) {
|
||||||
|
// Crap.
|
||||||
|
assert_always();
|
||||||
|
vkDestroyImage(*device_, image, nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = vkBindImageMemory(*device_, image, memory, 0);
|
||||||
|
CheckResult(err, "vkBindImageMemory");
|
||||||
|
|
||||||
|
auto texture = new Texture();
|
||||||
|
texture->format = image_info.format;
|
||||||
|
texture->image = image;
|
||||||
|
texture->image_layout = image_info.initialLayout;
|
||||||
|
texture->image_memory = memory;
|
||||||
|
texture->memory_offset = 0;
|
||||||
|
texture->memory_size = mem_requirements.size;
|
||||||
|
texture->texture_info = texture_info;
|
||||||
|
|
||||||
|
// Create a default view, just for kicks.
|
||||||
|
VkImageViewCreateInfo view_info;
|
||||||
|
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
view_info.pNext = nullptr;
|
||||||
|
view_info.flags = 0;
|
||||||
|
view_info.image = image;
|
||||||
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
view_info.format = image_info.format;
|
||||||
|
view_info.components = {
|
||||||
|
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
||||||
|
VK_COMPONENT_SWIZZLE_A,
|
||||||
|
};
|
||||||
|
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
|
VkImageView view;
|
||||||
|
err = vkCreateImageView(*device_, &view_info, nullptr, &view);
|
||||||
|
CheckResult(err, "vkCreateImageView");
|
||||||
|
if (err == VK_SUCCESS) {
|
||||||
|
auto texture_view = std::make_unique<TextureView>();
|
||||||
|
texture_view->texture = texture;
|
||||||
|
texture_view->view = view;
|
||||||
|
texture->views.push_back(std::move(texture_view));
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TextureCache::FreeTexture(Texture* texture) {
|
||||||
|
// TODO(DrChat)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureCache::Texture* TextureCache::DemandResolveTexture(
|
||||||
|
const TextureInfo& texture_info, TextureFormat format,
|
||||||
|
uint32_t* out_offset_x, uint32_t* out_offset_y) {
|
||||||
|
// Check to see if we've already used a texture at this location.
|
||||||
|
auto texture = LookupAddress(
|
||||||
|
texture_info.guest_address, texture_info.size_2d.block_width,
|
||||||
|
texture_info.size_2d.block_height, format, out_offset_x, out_offset_y);
|
||||||
|
if (texture) {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check resolve textures.
|
||||||
|
for (auto it = resolve_textures_.begin(); it != resolve_textures_.end();
|
||||||
|
++it) {
|
||||||
|
texture = (*it).get();
|
||||||
|
if (texture_info.guest_address == texture->texture_info.guest_address &&
|
||||||
|
texture_info.size_2d.logical_width ==
|
||||||
|
texture->texture_info.size_2d.logical_width &&
|
||||||
|
texture_info.size_2d.logical_height ==
|
||||||
|
texture->texture_info.size_2d.logical_height) {
|
||||||
|
// Exact match.
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No texture at this location. Make a new one.
|
||||||
|
texture = AllocateTexture(texture_info);
|
||||||
|
resolve_textures_.push_back(std::unique_ptr<Texture>(texture));
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
VkCommandBuffer command_buffer) {
|
VkCommandBuffer command_buffer) {
|
||||||
// Run a tight loop to scan for an existing texture.
|
// Run a tight loop to scan for an exact match existing texture.
|
||||||
auto texture_hash = texture_info.hash();
|
auto texture_hash = texture_info.hash();
|
||||||
for (auto it = textures_.find(texture_hash); it != textures_.end(); ++it) {
|
for (auto it = textures_.find(texture_hash); it != textures_.end(); ++it) {
|
||||||
if (it->second->texture_info == texture_info) {
|
if (it->second->texture_info == texture_info) {
|
||||||
|
@ -141,15 +275,25 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Though we didn't find an exact match, that doesn't mean we're out of the
|
// Check resolve textures.
|
||||||
// woods yet. This texture could either be a portion of another texture or
|
for (auto it = resolve_textures_.begin(); it != resolve_textures_.end();
|
||||||
// vice versa. Check for overlap before uploading.
|
++it) {
|
||||||
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
|
auto texture = (*it).get();
|
||||||
|
if (texture_info.guest_address == texture->texture_info.guest_address &&
|
||||||
|
texture_info.size_2d.logical_width ==
|
||||||
|
texture->texture_info.size_2d.logical_width &&
|
||||||
|
texture_info.size_2d.logical_height ==
|
||||||
|
texture->texture_info.size_2d.logical_height) {
|
||||||
|
// Exact match.
|
||||||
|
// TODO: Lazy match
|
||||||
|
texture->texture_info = texture_info;
|
||||||
|
textures_[texture_hash] = std::move(*it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!command_buffer) {
|
if (!command_buffer) {
|
||||||
// Texture not found and no command buffer was passed allowing us to upload
|
// Texture not found and no command buffer was passed, preventing us from
|
||||||
// a new one.
|
// uploading a new one.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +311,12 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Though we didn't find an exact match, that doesn't mean we're out of the
|
||||||
|
// woods yet. This texture could either be a portion of another texture or
|
||||||
|
// vice versa. Copy any overlapping textures into this texture.
|
||||||
|
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
|
||||||
|
}
|
||||||
|
|
||||||
textures_[texture_hash] = std::unique_ptr<Texture>(texture);
|
textures_[texture_hash] = std::unique_ptr<Texture>(texture);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
|
@ -199,7 +349,7 @@ TextureCache::Sampler* TextureCache::Demand(const SamplerInfo& sampler_info) {
|
||||||
sampler_create_info.anisotropyEnable = VK_FALSE;
|
sampler_create_info.anisotropyEnable = VK_FALSE;
|
||||||
sampler_create_info.maxAnisotropy = 1.0f;
|
sampler_create_info.maxAnisotropy = 1.0f;
|
||||||
sampler_create_info.compareEnable = VK_FALSE;
|
sampler_create_info.compareEnable = VK_FALSE;
|
||||||
sampler_create_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
sampler_create_info.compareOp = VK_COMPARE_OP_NEVER;
|
||||||
sampler_create_info.minLod = 0.0f;
|
sampler_create_info.minLod = 0.0f;
|
||||||
sampler_create_info.maxLod = 0.0f;
|
sampler_create_info.maxLod = 0.0f;
|
||||||
sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||||
|
@ -220,95 +370,21 @@ TextureCache::Sampler* TextureCache::Demand(const SamplerInfo& sampler_info) {
|
||||||
return sampler;
|
return sampler;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::Texture* TextureCache::AllocateTexture(TextureInfo texture_info) {
|
TextureCache::Texture* TextureCache::LookupAddress(
|
||||||
// Create an image first.
|
uint32_t guest_address, uint32_t width, uint32_t height,
|
||||||
VkImageCreateInfo image_info = {};
|
TextureFormat format, uint32_t* offset_x, uint32_t* offset_y) {
|
||||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
for (auto it = textures_.begin(); it != textures_.end(); ++it) {
|
||||||
switch (texture_info.dimension) {
|
const auto& texture_info = it->second->texture_info;
|
||||||
case Dimension::k1D:
|
if (texture_info.guest_address == guest_address &&
|
||||||
image_info.imageType = VK_IMAGE_TYPE_1D;
|
texture_info.dimension == Dimension::k2D &&
|
||||||
break;
|
texture_info.size_2d.input_width == width &&
|
||||||
case Dimension::k2D:
|
texture_info.size_2d.input_height == height) {
|
||||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
return it->second.get();
|
||||||
break;
|
}
|
||||||
case Dimension::k3D:
|
|
||||||
image_info.imageType = VK_IMAGE_TYPE_3D;
|
|
||||||
break;
|
|
||||||
case Dimension::kCube:
|
|
||||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
|
||||||
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert_unhandled_case(texture_info.dimension);
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Format
|
// TODO: Try to match at an offset.
|
||||||
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
|
return nullptr;
|
||||||
image_info.extent = {texture_info.width + 1, texture_info.height + 1,
|
|
||||||
texture_info.depth + 1};
|
|
||||||
image_info.mipLevels = 1;
|
|
||||||
image_info.arrayLayers = 1;
|
|
||||||
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
||||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
||||||
image_info.usage =
|
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
|
||||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
image_info.queueFamilyIndexCount = 0;
|
|
||||||
image_info.pQueueFamilyIndices = nullptr;
|
|
||||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
||||||
VkImage image;
|
|
||||||
auto err = vkCreateImage(*device_, &image_info, nullptr, &image);
|
|
||||||
CheckResult(err, "vkCreateImage");
|
|
||||||
|
|
||||||
VkMemoryRequirements mem_requirements;
|
|
||||||
vkGetImageMemoryRequirements(*device_, image, &mem_requirements);
|
|
||||||
|
|
||||||
// TODO: Use a circular buffer or something else to allocate this memory.
|
|
||||||
// The device has a limited amount (around 64) of memory allocations that we
|
|
||||||
// can make.
|
|
||||||
// Now that we have the size, back the image with GPU memory.
|
|
||||||
auto memory = device_->AllocateMemory(mem_requirements, 0);
|
|
||||||
err = vkBindImageMemory(*device_, image, memory, 0);
|
|
||||||
CheckResult(err, "vkBindImageMemory");
|
|
||||||
|
|
||||||
auto texture = new Texture();
|
|
||||||
texture->format = image_info.format;
|
|
||||||
texture->image = image;
|
|
||||||
texture->memory_offset = 0;
|
|
||||||
texture->memory_size = mem_requirements.size;
|
|
||||||
texture->texture_info = texture_info;
|
|
||||||
texture->texture_memory = memory;
|
|
||||||
|
|
||||||
// Create a default view, just for kicks.
|
|
||||||
VkImageViewCreateInfo view_info;
|
|
||||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
||||||
view_info.pNext = nullptr;
|
|
||||||
view_info.flags = 0;
|
|
||||||
view_info.image = image;
|
|
||||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
||||||
view_info.format = image_info.format;
|
|
||||||
view_info.components = {
|
|
||||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
|
||||||
VK_COMPONENT_SWIZZLE_A,
|
|
||||||
};
|
|
||||||
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
|
||||||
VkImageView view;
|
|
||||||
err = vkCreateImageView(*device_, &view_info, nullptr, &view);
|
|
||||||
CheckResult(err, "vkCreateImageView");
|
|
||||||
if (err == VK_SUCCESS) {
|
|
||||||
auto texture_view = std::make_unique<TextureView>();
|
|
||||||
texture_view->texture = texture;
|
|
||||||
texture_view->view = view;
|
|
||||||
texture->views.push_back(std::move(texture_view));
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TextureCache::FreeTexture(Texture* texture) {
|
|
||||||
// TODO(DrChat)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureCache::UploadTexture2D(VkCommandBuffer command_buffer,
|
bool TextureCache::UploadTexture2D(VkCommandBuffer command_buffer,
|
||||||
|
@ -359,8 +435,8 @@ bool TextureCache::UploadTexture2D(VkCommandBuffer command_buffer,
|
||||||
// For now, just transfer the grid we uploaded earlier into the texture.
|
// For now, just transfer the grid we uploaded earlier into the texture.
|
||||||
VkBufferImageCopy copy_region;
|
VkBufferImageCopy copy_region;
|
||||||
copy_region.bufferOffset = 0;
|
copy_region.bufferOffset = 0;
|
||||||
copy_region.bufferRowLength = 0;
|
copy_region.bufferRowLength = 2048;
|
||||||
copy_region.bufferImageHeight = 0;
|
copy_region.bufferImageHeight = 2048;
|
||||||
copy_region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
copy_region.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
|
||||||
copy_region.imageOffset = {0, 0, 0};
|
copy_region.imageOffset = {0, 0, 0};
|
||||||
copy_region.imageExtent = {dest->texture_info.width + 1,
|
copy_region.imageExtent = {dest->texture_info.width + 1,
|
||||||
|
@ -378,6 +454,7 @@ bool TextureCache::UploadTexture2D(VkCommandBuffer command_buffer,
|
||||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||||
nullptr, 1, &barrier);
|
nullptr, 1, &barrier);
|
||||||
|
|
||||||
|
dest->image_layout = barrier.newLayout;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,6 +504,8 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
VkWriteDescriptorSet descriptor_writes[4];
|
VkWriteDescriptorSet descriptor_writes[4];
|
||||||
std::memset(descriptor_writes, 0, sizeof(descriptor_writes));
|
std::memset(descriptor_writes, 0, sizeof(descriptor_writes));
|
||||||
uint32_t descriptor_write_count = 0;
|
uint32_t descriptor_write_count = 0;
|
||||||
|
/*
|
||||||
|
// TODO(DrChat): Do we really need to separate samplers and images here?
|
||||||
if (update_set_info->sampler_write_count) {
|
if (update_set_info->sampler_write_count) {
|
||||||
auto& sampler_write = descriptor_writes[descriptor_write_count++];
|
auto& sampler_write = descriptor_writes[descriptor_write_count++];
|
||||||
sampler_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
sampler_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
@ -438,6 +517,7 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
sampler_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
sampler_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
sampler_write.pImageInfo = update_set_info->sampler_infos;
|
sampler_write.pImageInfo = update_set_info->sampler_infos;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if (update_set_info->image_1d_write_count) {
|
if (update_set_info->image_1d_write_count) {
|
||||||
auto& image_write = descriptor_writes[descriptor_write_count++];
|
auto& image_write = descriptor_writes[descriptor_write_count++];
|
||||||
image_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
image_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
|
@ -446,7 +526,7 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
image_write.dstBinding = 1;
|
image_write.dstBinding = 1;
|
||||||
image_write.dstArrayElement = 0;
|
image_write.dstArrayElement = 0;
|
||||||
image_write.descriptorCount = update_set_info->image_1d_write_count;
|
image_write.descriptorCount = update_set_info->image_1d_write_count;
|
||||||
image_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
image_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
image_write.pImageInfo = update_set_info->image_1d_infos;
|
image_write.pImageInfo = update_set_info->image_1d_infos;
|
||||||
}
|
}
|
||||||
if (update_set_info->image_2d_write_count) {
|
if (update_set_info->image_2d_write_count) {
|
||||||
|
@ -457,7 +537,7 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
image_write.dstBinding = 2;
|
image_write.dstBinding = 2;
|
||||||
image_write.dstArrayElement = 0;
|
image_write.dstArrayElement = 0;
|
||||||
image_write.descriptorCount = update_set_info->image_2d_write_count;
|
image_write.descriptorCount = update_set_info->image_2d_write_count;
|
||||||
image_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
image_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
image_write.pImageInfo = update_set_info->image_2d_infos;
|
image_write.pImageInfo = update_set_info->image_2d_infos;
|
||||||
}
|
}
|
||||||
if (update_set_info->image_3d_write_count) {
|
if (update_set_info->image_3d_write_count) {
|
||||||
|
@ -468,7 +548,7 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
image_write.dstBinding = 3;
|
image_write.dstBinding = 3;
|
||||||
image_write.dstArrayElement = 0;
|
image_write.dstArrayElement = 0;
|
||||||
image_write.descriptorCount = update_set_info->image_3d_write_count;
|
image_write.descriptorCount = update_set_info->image_3d_write_count;
|
||||||
image_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
image_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
image_write.pImageInfo = update_set_info->image_3d_infos;
|
image_write.pImageInfo = update_set_info->image_3d_infos;
|
||||||
}
|
}
|
||||||
if (update_set_info->image_cube_write_count) {
|
if (update_set_info->image_cube_write_count) {
|
||||||
|
@ -479,7 +559,7 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
|
||||||
image_write.dstBinding = 4;
|
image_write.dstBinding = 4;
|
||||||
image_write.dstArrayElement = 0;
|
image_write.dstArrayElement = 0;
|
||||||
image_write.descriptorCount = update_set_info->image_cube_write_count;
|
image_write.descriptorCount = update_set_info->image_cube_write_count;
|
||||||
image_write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
image_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
image_write.pImageInfo = update_set_info->image_cube_infos;
|
image_write.pImageInfo = update_set_info->image_cube_infos;
|
||||||
}
|
}
|
||||||
if (descriptor_write_count) {
|
if (descriptor_write_count) {
|
||||||
|
@ -542,14 +622,11 @@ bool TextureCache::SetupTextureBinding(UpdateSetInfo* update_set_info,
|
||||||
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
||||||
texture_info.input_length);
|
texture_info.input_length);
|
||||||
|
|
||||||
auto& sampler_write =
|
|
||||||
update_set_info->sampler_infos[update_set_info->sampler_write_count++];
|
|
||||||
sampler_write.sampler = sampler->sampler;
|
|
||||||
|
|
||||||
auto& image_write =
|
auto& image_write =
|
||||||
update_set_info->image_2d_infos[update_set_info->image_2d_write_count++];
|
update_set_info->image_2d_infos[update_set_info->image_2d_write_count++];
|
||||||
image_write.imageView = texture->views[0]->view;
|
image_write.imageView = texture->views[0]->view;
|
||||||
image_write.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
image_write.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
image_write.sampler = sampler->sampler;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,30 @@ namespace vulkan {
|
||||||
//
|
//
|
||||||
class TextureCache {
|
class TextureCache {
|
||||||
public:
|
public:
|
||||||
|
struct TextureView;
|
||||||
|
|
||||||
|
// This represents an uploaded Vulkan texture.
|
||||||
|
struct Texture {
|
||||||
|
TextureInfo texture_info;
|
||||||
|
std::vector<std::unique_ptr<TextureView>> views;
|
||||||
|
|
||||||
|
// True if we know all info about this texture, false otherwise.
|
||||||
|
// (e.g. we resolve to system memory and may not know the full details about
|
||||||
|
// this texture)
|
||||||
|
bool full_texture;
|
||||||
|
VkFormat format;
|
||||||
|
VkImage image;
|
||||||
|
VkImageLayout image_layout;
|
||||||
|
VkDeviceMemory image_memory;
|
||||||
|
VkDeviceSize memory_offset;
|
||||||
|
VkDeviceSize memory_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TextureView {
|
||||||
|
Texture* texture;
|
||||||
|
VkImageView view;
|
||||||
|
};
|
||||||
|
|
||||||
TextureCache(RegisterFile* register_file, TraceWriter* trace_writer,
|
TextureCache(RegisterFile* register_file, TraceWriter* trace_writer,
|
||||||
ui::vulkan::VulkanDevice* device);
|
ui::vulkan::VulkanDevice* device);
|
||||||
~TextureCache();
|
~TextureCache();
|
||||||
|
@ -49,28 +73,24 @@ class TextureCache {
|
||||||
// TODO(benvanik): Resolve.
|
// TODO(benvanik): Resolve.
|
||||||
// TODO(benvanik): ReadTexture.
|
// TODO(benvanik): ReadTexture.
|
||||||
|
|
||||||
|
// Demands a texture for the purpose of resolving from EDRAM. This either
|
||||||
|
// creates a new texture or returns a previously created texture. texture_info
|
||||||
|
// is not required to be completely filled out, just guest_address and size.
|
||||||
|
//
|
||||||
|
// It's possible that this may return an image that is larger than the
|
||||||
|
// requested size (e.g. resolving into a bigger texture) or an image that
|
||||||
|
// must have an offset applied. If so, the caller must handle this.
|
||||||
|
// At the very least, it's guaranteed that the image will be large enough to
|
||||||
|
// hold the requested size.
|
||||||
|
Texture* DemandResolveTexture(const TextureInfo& texture_info,
|
||||||
|
TextureFormat format, uint32_t* out_offset_x,
|
||||||
|
uint32_t* out_offset_y);
|
||||||
|
|
||||||
// Clears all cached content.
|
// Clears all cached content.
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct UpdateSetInfo;
|
struct UpdateSetInfo;
|
||||||
struct TextureView;
|
|
||||||
|
|
||||||
// This represents an uploaded Vulkan texture.
|
|
||||||
struct Texture {
|
|
||||||
TextureInfo texture_info;
|
|
||||||
VkDeviceMemory texture_memory;
|
|
||||||
VkDeviceSize memory_offset;
|
|
||||||
VkDeviceSize memory_size;
|
|
||||||
VkImage image;
|
|
||||||
VkFormat format;
|
|
||||||
std::vector<std::unique_ptr<TextureView>> views;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureView {
|
|
||||||
Texture* texture;
|
|
||||||
VkImageView view;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Cached Vulkan sampler.
|
// Cached Vulkan sampler.
|
||||||
struct Sampler {
|
struct Sampler {
|
||||||
|
@ -78,18 +98,28 @@ class TextureCache {
|
||||||
VkSampler sampler;
|
VkSampler sampler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allocates a new texture and memory to back it on the GPU.
|
||||||
|
Texture* AllocateTexture(const TextureInfo& texture_info);
|
||||||
|
bool FreeTexture(Texture* texture);
|
||||||
|
|
||||||
// Demands a texture. If command_buffer is null and the texture hasn't been
|
// Demands a texture. If command_buffer is null and the texture hasn't been
|
||||||
// uploaded to graphics memory already, we will return null and bail.
|
// uploaded to graphics memory already, we will return null and bail.
|
||||||
Texture* Demand(const TextureInfo& texture_info,
|
Texture* Demand(const TextureInfo& texture_info,
|
||||||
VkCommandBuffer command_buffer = nullptr);
|
VkCommandBuffer command_buffer = nullptr);
|
||||||
Sampler* Demand(const SamplerInfo& sampler_info);
|
Sampler* Demand(const SamplerInfo& sampler_info);
|
||||||
|
|
||||||
// Allocates a new texture and memory to back it on the GPU.
|
// Looks for a texture either containing or matching these parameters.
|
||||||
Texture* AllocateTexture(TextureInfo texture_info);
|
// Caller is responsible for checking if the texture returned is an exact
|
||||||
bool FreeTexture(Texture* texture);
|
// match or just contains the texture given by the parameters.
|
||||||
|
// If offset_x and offset_y are not null, this may return a texture that
|
||||||
|
// contains this image at an offset.
|
||||||
|
Texture* LookupAddress(uint32_t guest_address, uint32_t width,
|
||||||
|
uint32_t height, TextureFormat format,
|
||||||
|
uint32_t* offset_x, uint32_t* offset_y);
|
||||||
|
|
||||||
// Queues commands to upload a texture from system memory, applying any
|
// Queues commands to upload a texture from system memory, applying any
|
||||||
// conversions necessary.
|
// conversions necessary. This may flush the command buffer to the GPU if we
|
||||||
|
// run out of staging memory.
|
||||||
bool UploadTexture2D(VkCommandBuffer command_buffer, Texture* dest,
|
bool UploadTexture2D(VkCommandBuffer command_buffer, Texture* dest,
|
||||||
TextureInfo src);
|
TextureInfo src);
|
||||||
|
|
||||||
|
@ -112,13 +142,12 @@ class TextureCache {
|
||||||
VkDeviceMemory staging_buffer_mem_ = nullptr;
|
VkDeviceMemory staging_buffer_mem_ = nullptr;
|
||||||
std::unordered_map<uint64_t, std::unique_ptr<Texture>> textures_;
|
std::unordered_map<uint64_t, std::unique_ptr<Texture>> textures_;
|
||||||
std::unordered_map<uint64_t, std::unique_ptr<Sampler>> samplers_;
|
std::unordered_map<uint64_t, std::unique_ptr<Sampler>> samplers_;
|
||||||
|
std::vector<std::unique_ptr<Texture>> resolve_textures_;
|
||||||
|
|
||||||
struct UpdateSetInfo {
|
struct UpdateSetInfo {
|
||||||
// Bitmap of all 32 fetch constants and whether they have been setup yet.
|
// Bitmap of all 32 fetch constants and whether they have been setup yet.
|
||||||
// This prevents duplication across the vertex and pixel shader.
|
// This prevents duplication across the vertex and pixel shader.
|
||||||
uint32_t has_setup_fetch_mask;
|
uint32_t has_setup_fetch_mask;
|
||||||
uint32_t sampler_write_count = 0;
|
|
||||||
VkDescriptorImageInfo sampler_infos[32];
|
|
||||||
uint32_t image_1d_write_count = 0;
|
uint32_t image_1d_write_count = 0;
|
||||||
VkDescriptorImageInfo image_1d_infos[32];
|
VkDescriptorImageInfo image_1d_infos[32];
|
||||||
uint32_t image_2d_write_count = 0;
|
uint32_t image_2d_write_count = 0;
|
||||||
|
|
Loading…
Reference in New Issue