Texture region splitting

Introduce the concept of texture regions. Each texture starts with a base
region which covers all of its content, and can provide smaller subregions
given an offset and size (populated by allocating a new VkImage and blitting
from the base region). Subregion allocations and content are cached and
invalidated when the base region is written. Writing is only allowed to the
base region at this time.
This commit is contained in:
Dan Weatherford 2017-09-25 22:31:42 -05:00 committed by DrChat
parent 2e3329095b
commit 277b9dd9ae
3 changed files with 272 additions and 121 deletions

View File

@ -233,12 +233,13 @@ void TextureCache::Shutdown() {
nullptr);
}
TextureCache::Texture* TextureCache::AllocateTexture(
const TextureInfo& texture_info, VkFormatFeatureFlags required_flags) {
TextureCache::TextureRegion* TextureCache::AllocateTextureRegion(
Texture* texture, VkOffset3D region_offset, VkExtent3D region_size,
VkFormatFeatureFlags required_flags) {
// Create an image first.
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
switch (texture_info.dimension) {
switch (texture->texture_info.dimension) {
case Dimension::k1D:
case Dimension::k2D:
image_info.imageType = VK_IMAGE_TYPE_2D;
@ -251,36 +252,28 @@ TextureCache::Texture* TextureCache::AllocateTexture(
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
break;
default:
assert_unhandled_case(texture_info.dimension);
assert_unhandled_case(texture->texture_info.dimension);
return nullptr;
}
assert_not_null(texture_info.format_info());
auto& config = texture_configs[int(texture_info.format_info()->format)];
VkFormat format = config.host_format;
assert(format != VK_FORMAT_UNDEFINED);
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage =
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
// Check the device limits for the format before we create it.
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(*device_, format, &props);
vkGetPhysicalDeviceFormatProperties(*device_, texture->format, &props);
if ((props.optimalTilingFeatures & required_flags) != required_flags) {
// Texture needs conversion on upload to a native format.
XELOGE(
"Texture Cache: Invalid usage flag specified on format %s (%s)\n\t"
"(requested: %s)",
texture_info.format_info()->name, ui::vulkan::to_string(format),
ui::vulkan::to_flags_string(
static_cast<VkFormatFeatureFlagBits>(required_flags &
~props.optimalTilingFeatures))
.c_str());
"Texture Cache: Invalid usage flag specified on format %s (vk %d) "
"(0x%.8X != 0x%.8X)",
texture->texture_info.format_info()->name, texture->format,
(props.optimalTilingFeatures & required_flags), required_flags);
assert_always();
}
if (texture_info.dimension != Dimension::kCube &&
if (texture->texture_info.dimension != Dimension::kCube &&
props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
// Add color attachment usage if it's supported.
image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
@ -296,43 +289,73 @@ TextureCache::Texture* TextureCache::AllocateTexture(
VkImageFormatProperties image_props;
vkGetPhysicalDeviceImageFormatProperties(
*device_, format, image_info.imageType, image_info.tiling,
*device_, texture->format, image_info.imageType, image_info.tiling,
image_info.usage, image_info.flags, &image_props);
// TODO(DrChat): Actually check the image properties.
image_info.format = format;
image_info.extent = {texture_info.width + 1, texture_info.height + 1, 1};
image_info.format = texture->format;
image_info.extent = region_size;
image_info.mipLevels = 1;
image_info.arrayLayers = texture_info.depth + 1;
image_info.arrayLayers = texture->texture_info.depth + 1;
image_info.samples = VK_SAMPLE_COUNT_1_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;
VmaAllocation alloc;
VmaAllocation allocation;
VmaAllocationCreateInfo vma_create_info = {
0, VMA_MEMORY_USAGE_GPU_ONLY, 0, 0, 0, nullptr, nullptr,
};
VmaAllocationInfo vma_info = {};
VkResult status = vmaCreateImage(mem_allocator_, &image_info,
&vma_create_info, &image, &alloc, &vma_info);
VkResult status = vmaCreateImage(mem_allocator_, &image_info, &vma_reqs,
&image, &allocation, &vma_info);
if (status != VK_SUCCESS) {
// Allocation failed.
return nullptr;
}
TextureRegion* region = new TextureRegion();
region->texture = texture;
region->region_offset = region_offset;
region->region_size = region_size;
region->image = image;
region->image_layout = image_info.initialLayout;
region->allocation = allocation;
region->allocation_info = vma_info;
region->region_contents_valid = false;
texture->regions.push_back(std::unique_ptr<TextureRegion>(region));
return region;
}
TextureCache::Texture* TextureCache::AllocateTexture(
const TextureInfo& texture_info, VkFormatFeatureFlags required_flags) {
VkOffset3D region_offset = {0, 0, 0};
VkExtent3D region_extent = {texture_info.width + 1, texture_info.height + 1,
1};
auto texture = new Texture();
texture->format = image_info.format;
texture->image = image;
texture->image_layout = image_info.initialLayout;
texture->alloc = alloc;
texture->alloc_info = vma_info;
texture->framebuffer = nullptr;
texture->access_watch_handle = 0;
texture->texture_info = texture_info;
assert_not_null(texture->texture_info.format_info());
auto& config =
texture_configs[int(texture->texture_info.format_info()->format)];
texture->format = config.host_format != VK_FORMAT_UNDEFINED
? config.host_format
: VK_FORMAT_R8G8B8A8_UNORM;
TextureRegion* base_region = AllocateTextureRegion(
texture, region_offset, region_extent, required_flags);
texture->base_region = base_region;
return texture;
}
@ -349,9 +372,14 @@ bool TextureCache::FreeTexture(Texture* texture) {
vkDestroyFramebuffer(*device_, texture->framebuffer, nullptr);
}
for (auto it = texture->views.begin(); it != texture->views.end();) {
vkDestroyImageView(*device_, (*it)->view, nullptr);
it = texture->views.erase(it);
for (auto region_it = texture->regions.begin();
region_it != texture->regions.end(); ++region_it) {
TextureRegion* region = region_it->get();
for (auto view_it = region->views.begin(); view_it != region->views.end();
++view_it) {
vkDestroyImageView(*device_, (*view_it)->view, nullptr);
}
vmaDestroyImage(mem_allocator_, region->image, region->allocation);
}
if (texture->access_watch_handle) {
@ -359,7 +387,6 @@ bool TextureCache::FreeTexture(Texture* texture) {
texture->access_watch_handle = 0;
}
vmaDestroyImage(mem_allocator_, texture->image, texture->alloc);
delete texture;
return true;
}
@ -418,7 +445,7 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
// Setup a debug name for the texture.
device_->DbgSetObjectName(
reinterpret_cast<uint64_t>(texture->image),
reinterpret_cast<uint64_t>(texture->base_region->image),
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
xe::format_string(
"0x%.8X - 0x%.8X", texture_info.guest_address,
@ -434,9 +461,9 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
return texture;
}
TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
VkCommandBuffer command_buffer,
VkFence completion_fence) {
TextureCache::TextureRegion* TextureCache::DemandRegion(
const TextureInfo& texture_info, VkCommandBuffer command_buffer,
VkFence completion_fence) {
// Run a tight loop to scan for an exact match existing texture.
auto texture_hash = texture_info.hash();
for (auto it = textures_.find(texture_hash); it != textures_.end(); ++it) {
@ -450,7 +477,7 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
trace_writer_->WriteMemoryReadCached(texture_info.guest_address,
texture_info.input_length);
return it->second;
return it->second->base_region;
}
}
@ -460,8 +487,102 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
return nullptr;
}
// If we didn't find an exact match, see if we can find a subregion of an
// existing texture to use.
VkOffset2D offset;
auto containing_tex = LookupAddress(
texture_info.guest_address, texture_info.width + 1,
texture_info.height + 1, texture_info.format_info()->format, &offset);
if (containing_tex != nullptr) {
// Found a larger texture that contains the requested texels.
// Find/create/update a matching subregion.
// First, see if the region exists
TextureRegion* region = nullptr;
for (auto region_it = containing_tex->regions.begin();
region_it != containing_tex->regions.end(); ++region_it) {
const VkOffset3D& roffset = (*region_it)->region_offset;
const VkExtent3D& rsize = (*region_it)->region_size;
if (roffset.x == offset.x && roffset.y == offset.y &&
rsize.width == (texture_info.width + 1) &&
rsize.height == (texture_info.height + 1)) {
// Match found
region = region_it->get();
break;
}
}
if (!region) {
// No match, create a new region and add it the texture
region = AllocateTextureRegion(
containing_tex, {offset.x, offset.y, 0},
{texture_info.width + 1, texture_info.height + 1, 1},
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
}
if (!region->region_contents_valid) {
// Region content is out-of-date, recreate it by blitting from the base
// region.
// Transition the region into a transfer destination layout.
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.pNext = nullptr;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = region->image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
if (containing_tex->format == VK_FORMAT_D16_UNORM_S8_UINT ||
containing_tex->format == VK_FORMAT_D24_UNORM_S8_UINT ||
containing_tex->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
barrier.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
}
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
// Now move the converted texture into the destination.
VkImageCopy copy_region;
copy_region.srcSubresource = {barrier.subresourceRange.aspectMask, 0, 0,
1};
copy_region.dstSubresource = {barrier.subresourceRange.aspectMask, 0, 0,
1};
copy_region.srcOffset = {offset.x, offset.y, 0};
copy_region.dstOffset = {0, 0, 0};
copy_region.extent = {texture_info.width + 1, texture_info.height + 1, 1};
vkCmdCopyImage(command_buffer, containing_tex->base_region->image,
containing_tex->base_region->image_layout, region->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
// Now transition the region into a shader readonly source.
barrier.srcAccessMask = barrier.dstAccessMask;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = barrier.newLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
region->image_layout = barrier.newLayout;
// Mark contents as up-to-date
region->region_contents_valid = true;
}
return region;
}
// Create a new texture and cache it.
auto texture = AllocateTexture(texture_info);
auto texture =
AllocateTexture(texture_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
if (!texture) {
// Failed to allocate texture (out of memory?)
assert_always();
@ -469,18 +590,6 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
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.
// TODO: Byte count -> pixel count (on x and y axes)
VkOffset2D offset;
auto collide_tex = LookupAddress(
texture_info.guest_address, texture_info.width + 1,
texture_info.height + 1, texture_info.format_info()->format, &offset);
if (collide_tex != nullptr) {
// assert_always();
}
trace_writer_->WriteMemoryRead(texture_info.guest_address,
texture_info.input_length);
@ -497,7 +606,7 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
// Setup a debug name for the texture.
device_->DbgSetObjectName(
reinterpret_cast<uint64_t>(texture->image),
reinterpret_cast<uint64_t>(texture->base_region->image),
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
xe::format_string(
"0x%.8X - 0x%.8X", texture_info.guest_address,
@ -505,12 +614,12 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
textures_[texture_hash] = texture;
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
return texture;
return texture->base_region;
}
TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
uint16_t swizzle) {
for (auto it = texture->views.begin(); it != texture->views.end(); ++it) {
TextureCache::TextureRegionView* TextureCache::DemandTextureRegionView(
TextureRegion* region, uint16_t swizzle) {
for (auto it = region->views.begin(); it != region->views.end(); ++it) {
if ((*it)->swizzle == swizzle) {
return (*it).get();
}
@ -520,10 +629,10 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.pNext = nullptr;
view_info.flags = 0;
view_info.image = texture->image;
view_info.format = texture->format;
view_info.image = region->image;
view_info.format = region->texture->format;
switch (texture->texture_info.dimension) {
switch (region->texture->texture_info.dimension) {
case Dimension::k1D:
case Dimension::k2D:
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
@ -552,14 +661,14 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
swiz_component_map[(swizzle >> 9) & 0x7],
};
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
if (texture->format == VK_FORMAT_D16_UNORM_S8_UINT ||
texture->format == VK_FORMAT_D24_UNORM_S8_UINT ||
texture->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
if (region->texture->format == VK_FORMAT_D16_UNORM_S8_UINT ||
region->texture->format == VK_FORMAT_D24_UNORM_S8_UINT ||
region->texture->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
// This applies to any depth/stencil format, but we only use D24S8 / D32FS8.
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
if (texture->texture_info.dimension == Dimension::kCube) {
if (region->texture->texture_info.dimension == Dimension::kCube) {
view_info.subresourceRange.layerCount = 6;
}
@ -567,12 +676,12 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
auto status = vkCreateImageView(*device_, &view_info, nullptr, &view);
CheckResult(status, "vkCreateImageView");
if (status == VK_SUCCESS) {
auto texture_view = new TextureView();
texture_view->texture = texture;
texture_view->view = view;
texture_view->swizzle = swizzle;
texture->views.push_back(std::unique_ptr<TextureView>(texture_view));
return texture_view;
auto region_view = new TextureRegionView();
region_view->region = region;
region_view->view = view;
region_view->swizzle = swizzle;
region->views.push_back(std::unique_ptr<TextureRegionView>(region_view));
return region_view;
}
return nullptr;
@ -1115,7 +1224,8 @@ bool TextureCache::ComputeTextureStorage(size_t* output_length,
void TextureCache::WritebackTexture(Texture* texture) {
VkResult status = VK_SUCCESS;
VkFence fence = wb_command_pool_->BeginBatch();
auto alloc = wb_staging_buffer_.Acquire(texture->alloc_info.size, fence);
auto alloc = wb_staging_buffer_.Acquire(
texture->base_region->allocation_info.size, fence);
if (!alloc) {
wb_command_pool_->EndBatch();
return;
@ -1142,7 +1252,7 @@ void TextureCache::WritebackTexture(Texture* texture) {
{texture->texture_info.width + 1, texture->texture_info.height + 1, 1},
};
vkCmdCopyImageToBuffer(command_buffer, texture->image,
vkCmdCopyImageToBuffer(command_buffer, texture->base_region->image,
VK_IMAGE_LAYOUT_GENERAL,
wb_staging_buffer_.gpu_buffer(), 1, &region);
@ -1235,6 +1345,14 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
src.guest_address, src.input_length, src.texture_format);
}
// Invalidate contents of all regions for this texture, except for the base
// region.
for (auto region_it = dest->regions.begin(); region_it != dest->regions.end();
++region_it) {
(*region_it)->region_contents_valid = false;
}
dest->base_region->region_contents_valid = true;
// Upload texture into GPU memory.
// TODO: If the GPU supports it, we can submit a compute batch to convert the
// texture and copy it to its destination. Otherwise, fallback to conversion
@ -1252,11 +1370,11 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
barrier.pNext = nullptr;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = dest->image_layout;
barrier.oldLayout = dest->base_region->image_layout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = dest->image;
barrier.image = dest->base_region->image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1,
copy_region.imageSubresource.baseArrayLayer,
copy_region.imageSubresource.layerCount};
@ -1281,8 +1399,8 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
vkCmdCopyBufferToImage(command_buffer, staging_buffer_.gpu_buffer(),
dest->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
&copy_region);
dest->base_region->image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
// Now transition the texture into a shader readonly source.
barrier.srcAccessMask = barrier.dstAccessMask;
@ -1294,7 +1412,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0, 0, nullptr, 0, nullptr, 1, &barrier);
dest->image_layout = barrier.newLayout;
dest->base_region->image_layout = barrier.newLayout;
return true;
}
@ -1435,14 +1553,15 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
// Search via the base format.
texture_info.texture_format = GetBaseFormat(texture_info.texture_format);
auto texture = Demand(texture_info, command_buffer, completion_fence);
auto texture_region =
DemandRegion(texture_info, command_buffer, completion_fence);
auto sampler = Demand(sampler_info);
if (texture == nullptr || sampler == nullptr) {
if (texture_region == nullptr || sampler == nullptr) {
return false;
}
uint16_t swizzle = static_cast<uint16_t>(fetch.swizzle);
auto view = DemandView(texture, swizzle);
auto view = DemandTextureRegionView(texture_region, swizzle);
auto image_info =
&update_set_info->image_infos[update_set_info->image_write_count];
@ -1465,9 +1584,9 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
image_write->pTexelBufferView = nullptr;
image_info->imageView = view->view;
image_info->imageLayout = texture->image_layout;
image_info->imageLayout = texture_region->image_layout;
image_info->sampler = sampler->sampler;
texture->in_flight_fence = completion_fence;
texture_region->texture->in_flight_fence = completion_fence;
return true;
}

View File

@ -34,29 +34,11 @@ namespace vulkan {
//
class TextureCache {
public:
struct TextureView;
struct TextureRegion;
struct Texture;
// This represents an uploaded Vulkan texture.
struct Texture {
TextureInfo texture_info;
std::vector<std::unique_ptr<TextureView>> views;
VkFormat format;
VkImage image;
VkImageLayout image_layout;
VmaAllocation alloc;
VmaAllocationInfo alloc_info;
VkFramebuffer framebuffer; // Blit target frame buffer.
uintptr_t access_watch_handle;
bool pending_invalidation;
// Pointer to the latest usage fence.
VkFence in_flight_fence;
};
struct TextureView {
Texture* texture;
struct TextureRegionView {
TextureRegion* region;
VkImageView view;
union {
@ -73,6 +55,43 @@ class TextureCache {
};
};
struct TextureRegion {
Texture* texture;
std::vector<std::unique_ptr<TextureRegionView>> views;
VkOffset3D region_offset;
VkExtent3D region_size;
VkImage image;
VkImageLayout image_layout;
VmaAllocation allocation;
VmaAllocationInfo allocation_info;
bool region_contents_valid;
};
// This represents an uploaded Vulkan texture. A texture has a base image
// region containing its full content area, and zero or more regions
// that are crops of that base region.
struct Texture {
TextureInfo texture_info;
VkFormat format;
std::vector<std::unique_ptr<TextureRegion>> regions;
// Non-owning; base region is also in the (owning) regions vector.
TextureRegion* base_region;
VkFramebuffer framebuffer; // Blit target frame buffer.
uintptr_t access_watch_handle;
bool pending_invalidation;
// Pointer to the latest usage fence.
VkFence in_flight_fence;
};
TextureCache(Memory* memory, RegisterFile* register_file,
TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device);
~TextureCache();
@ -108,7 +127,7 @@ class TextureCache {
uint32_t height, TextureFormat format,
VkOffset2D* out_offset = nullptr);
TextureView* DemandView(Texture* texture, uint16_t swizzle);
TextureRegionView* DemandTextureRegionView(TextureRegion*, uint16_t swizzle);
// Demands a texture for the purpose of resolving from EDRAM. This either
// creates a new texture or returns a previously created texture.
@ -131,18 +150,20 @@ class TextureCache {
// Allocates a new texture and memory to back it on the GPU.
Texture* AllocateTexture(const TextureInfo& texture_info,
VkFormatFeatureFlags required_flags =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
VkFormatFeatureFlags required_flags);
bool FreeTexture(Texture* texture);
static void WatchCallback(void* context_ptr, void* data_ptr,
uint32_t address);
TextureRegion* AllocateTextureRegion(Texture*, VkOffset3D region_offset,
VkExtent3D region_size,
VkFormatFeatureFlags required_flags);
// 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.
Texture* Demand(const TextureInfo& texture_info,
VkCommandBuffer command_buffer = nullptr,
VkFence completion_fence = nullptr);
TextureRegion* DemandRegion(const TextureInfo& texture_info,
VkCommandBuffer command_buffer = nullptr,
VkFence completion_fence = nullptr);
Sampler* Demand(const SamplerInfo& sampler_info);
void FlushPendingCommands(VkCommandBuffer command_buffer,

View File

@ -436,11 +436,11 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
barrier.srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.oldLayout = texture->image_layout;
barrier.newLayout = texture->image_layout;
barrier.oldLayout = texture->base_region->image_layout;
barrier.newLayout = texture->base_region->image_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = texture->image;
barrier.image = texture->base_region->image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vkCmdPipelineBarrier(copy_commands,
@ -473,7 +473,9 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
blitter_->BlitTexture2D(
copy_commands, current_batch_fence_,
texture_cache_->DemandView(texture, 0x688)->view, src_rect,
texture_cache_->DemandTextureRegionView(texture->base_region, 0x688)
->view,
src_rect,
{texture->texture_info.width + 1, texture->texture_info.height + 1},
VK_FORMAT_R8G8B8A8_UNORM, dst_rect,
{frontbuffer_width, frontbuffer_height}, fb_framebuffer_, viewport,
@ -825,7 +827,7 @@ bool VulkanCommandProcessor::PopulateSamplers(VkCommandBuffer command_buffer,
std::vector<xe::gpu::Shader::TextureBinding> dummy_bindings;
auto descriptor_set = texture_cache_->PrepareTextureSet(
setup_buffer, current_batch_fence_, vertex_shader->texture_bindings(),
command_buffer, current_batch_fence_, vertex_shader->texture_bindings(),
pixel_shader ? pixel_shader->texture_bindings() : dummy_bindings);
if (!descriptor_set) {
// Unable to bind set.
@ -1039,7 +1041,15 @@ bool VulkanCommandProcessor::IssueCopy() {
}
auto command_buffer = current_command_buffer_;
if (texture->image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
// Mark all regions of the texture (except base region, which we will write
// to) as invalid
for (auto region_it = texture->regions.begin();
region_it != texture->regions.end(); ++region_it) {
(*region_it)->region_contents_valid = false;
}
texture->base_region->region_contents_valid = true;
if (texture->base_region->image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
// Transition the image to a general layout.
VkImageMemoryBarrier image_barrier;
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@ -1050,13 +1060,13 @@ bool VulkanCommandProcessor::IssueCopy() {
image_barrier.dstAccessMask = 0;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.image = texture->image;
image_barrier.image = texture->base_region->image;
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
image_barrier.subresourceRange.aspectMask =
is_color_source
? VK_IMAGE_ASPECT_COLOR_BIT
: VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
texture->image_layout = VK_IMAGE_LAYOUT_GENERAL;
texture->base_region->image_layout = VK_IMAGE_LAYOUT_GENERAL;
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0,
@ -1074,11 +1084,11 @@ bool VulkanCommandProcessor::IssueCopy() {
image_barrier.dstAccessMask =
is_color_source ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
: VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
image_barrier.oldLayout = texture->image_layout;
image_barrier.oldLayout = texture->base_region->image_layout;
image_barrier.newLayout =
is_color_source ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
image_barrier.image = texture->image;
image_barrier.image = texture->base_region->image;
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
image_barrier.subresourceRange.aspectMask =
is_color_source ? VK_IMAGE_ASPECT_COLOR_BIT
@ -1152,7 +1162,8 @@ bool VulkanCommandProcessor::IssueCopy() {
// Create a framebuffer containing our image.
if (!texture->framebuffer) {
auto texture_view = texture_cache_->DemandView(texture, 0x688);
auto texture_view = texture_cache_->DemandTextureRegionView(
texture->base_region, 0x688);
VkFramebufferCreateInfo fb_create_info = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,