[UI] Image post-processing and full presentation/window rework

[GPU] Add FXAA post-processing
[UI] Add FidelityFX FSR and CAS post-processing
[UI] Add blue noise dithering from 10bpc to 8bpc
[GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color
[UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event
[UI] Allow variable refresh rate (or tearing)
[UI] Present the newest frame (restart) on DXGI
[UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management
[UI] Connect presentation to windows via the Surface class, not native window handles
[Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around
[Vulkan] Lower the minimum required Vulkan version to 1.0
[UI/GPU] Various cleanup, mainly ComPtr usage
[UI] Support per-monitor DPI awareness v2 on Windows
[UI] DPI-scale Dear ImGui
[UI] Replace the remaining non-detachable window delegates with unified window event and input listeners
[UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem
[UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing
[UI] Add explicit window lifecycle phases
[UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback
[UI] GTK: Apply the initial size to the drawing area
[UI] Limit internal UI frame rate to that of the monitor
[UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
This commit is contained in:
Triang3l
2022-01-29 13:22:03 +03:00
parent 372bdd3ec9
commit fe3f0f26e4
428 changed files with 75942 additions and 18360 deletions

View File

@@ -16,6 +16,7 @@
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_util.h"
using namespace xe::gpu::xenos;
@@ -91,16 +92,17 @@ void copy_cmp_swap_32_unaligned(void* dest_ptr, const void* src_ptr,
}
#endif
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
constexpr VkDeviceSize kConstantRegisterUniformRange =
512 * 4 * 4 + 8 * 4 + 32 * 4;
BufferCache::BufferCache(RegisterFile* register_file, Memory* memory,
ui::vulkan::VulkanDevice* device, size_t capacity)
: register_file_(register_file), memory_(memory), device_(device) {
const ui::vulkan::VulkanProvider& provider,
size_t capacity)
: register_file_(register_file), memory_(memory), provider_(provider) {
transient_buffer_ = std::make_unique<ui::vulkan::CircularBuffer>(
device_,
provider_,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
capacity, 256);
@@ -109,23 +111,41 @@ BufferCache::BufferCache(RegisterFile* register_file, Memory* memory,
BufferCache::~BufferCache() { Shutdown(); }
VkResult BufferCache::Initialize() {
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
VkMemoryRequirements pool_reqs;
transient_buffer_->GetBufferMemoryRequirements(&pool_reqs);
gpu_memory_pool_ = device_->AllocateMemory(pool_reqs);
VkMemoryAllocateInfo pool_allocate_info;
pool_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
pool_allocate_info.pNext = nullptr;
pool_allocate_info.allocationSize = pool_reqs.size;
pool_allocate_info.memoryTypeIndex = ui::vulkan::util::ChooseHostMemoryType(
provider_, pool_reqs.memoryTypeBits, false);
if (pool_allocate_info.memoryTypeIndex == UINT32_MAX) {
return VK_ERROR_INITIALIZATION_FAILED;
}
status = dfn.vkAllocateMemory(device, &pool_allocate_info, nullptr,
&gpu_memory_pool_);
if (status != VK_SUCCESS) {
return status;
}
VkResult status = transient_buffer_->Initialize(gpu_memory_pool_, 0);
status = transient_buffer_->Initialize(gpu_memory_pool_, 0);
if (status != VK_SUCCESS) {
return status;
}
// Create a memory allocator for textures.
VmaVulkanFunctions vulkan_funcs = {};
ui::vulkan::FillVMAVulkanFunctions(&vulkan_funcs, *device_);
VmaAllocatorCreateInfo alloc_info = {
0, *device_, *device_, 0, 0, nullptr, nullptr, 0, nullptr, &vulkan_funcs,
};
ui::vulkan::FillVMAVulkanFunctions(&vulkan_funcs, provider_);
VmaAllocatorCreateInfo alloc_info = {};
alloc_info.physicalDevice = provider_.physical_device();
alloc_info.device = device;
alloc_info.pVulkanFunctions = &vulkan_funcs;
alloc_info.instance = provider_.instance();
status = vmaCreateAllocator(&alloc_info, &mem_allocator_);
if (status != VK_SUCCESS) {
return status;
@@ -145,7 +165,8 @@ VkResult BufferCache::Initialize() {
}
VkResult BufferCache::CreateVertexDescriptorPool() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status;
std::vector<VkDescriptorPoolSize> pool_sizes;
@@ -154,7 +175,7 @@ VkResult BufferCache::CreateVertexDescriptorPool() {
32 * 16384,
});
vertex_descriptor_pool_ = std::make_unique<ui::vulkan::DescriptorPool>(
*device_, 32 * 16384, pool_sizes);
provider_, 32 * 16384, pool_sizes);
// 32 storage buffers available to vertex shader.
// TODO(DrChat): In the future, this could hold memexport staging data.
@@ -171,7 +192,7 @@ VkResult BufferCache::CreateVertexDescriptorPool() {
1,
&binding,
};
status = dfn.vkCreateDescriptorSetLayout(*device_, &layout_info, nullptr,
status = dfn.vkCreateDescriptorSetLayout(device, &layout_info, nullptr,
&vertex_descriptor_set_layout_);
if (status != VK_SUCCESS) {
return status;
@@ -183,13 +204,15 @@ VkResult BufferCache::CreateVertexDescriptorPool() {
void BufferCache::FreeVertexDescriptorPool() {
vertex_descriptor_pool_.reset();
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout, *device_,
vertex_descriptor_set_layout_);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout,
device, vertex_descriptor_set_layout_);
}
VkResult BufferCache::CreateConstantDescriptorSet() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
// Descriptor pool used for all of our cached descriptors.
@@ -207,7 +230,7 @@ VkResult BufferCache::CreateConstantDescriptorSet() {
pool_sizes[0].descriptorCount = 2;
transient_descriptor_pool_info.poolSizeCount = 1;
transient_descriptor_pool_info.pPoolSizes = pool_sizes;
status = dfn.vkCreateDescriptorPool(*device_, &transient_descriptor_pool_info,
status = dfn.vkCreateDescriptorPool(device, &transient_descriptor_pool_info,
nullptr, &constant_descriptor_pool_);
if (status != VK_SUCCESS) {
return status;
@@ -240,8 +263,8 @@ VkResult BufferCache::CreateConstantDescriptorSet() {
descriptor_set_layout_info.bindingCount =
static_cast<uint32_t>(xe::countof(bindings));
descriptor_set_layout_info.pBindings = bindings;
status = dfn.vkCreateDescriptorSetLayout(*device_,
&descriptor_set_layout_info, nullptr,
status = dfn.vkCreateDescriptorSetLayout(device, &descriptor_set_layout_info,
nullptr,
&constant_descriptor_set_layout_);
if (status != VK_SUCCESS) {
return status;
@@ -256,7 +279,7 @@ VkResult BufferCache::CreateConstantDescriptorSet() {
set_alloc_info.descriptorPool = constant_descriptor_pool_;
set_alloc_info.descriptorSetCount = 1;
set_alloc_info.pSetLayouts = &constant_descriptor_set_layout_;
status = dfn.vkAllocateDescriptorSets(*device_, &set_alloc_info,
status = dfn.vkAllocateDescriptorSets(device, &set_alloc_info,
&constant_descriptor_set_);
if (status != VK_SUCCESS) {
return status;
@@ -289,24 +312,26 @@ VkResult BufferCache::CreateConstantDescriptorSet() {
fragment_uniform_binding_write.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
fragment_uniform_binding_write.pBufferInfo = &buffer_info;
dfn.vkUpdateDescriptorSets(*device_, 2, descriptor_writes, 0, nullptr);
dfn.vkUpdateDescriptorSets(device, 2, descriptor_writes, 0, nullptr);
return VK_SUCCESS;
}
void BufferCache::FreeConstantDescriptorSet() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
if (constant_descriptor_set_) {
dfn.vkFreeDescriptorSets(*device_, constant_descriptor_pool_, 1,
dfn.vkFreeDescriptorSets(device, constant_descriptor_pool_, 1,
&constant_descriptor_set_);
constant_descriptor_set_ = nullptr;
}
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout, *device_,
constant_descriptor_set_layout_);
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyDescriptorPool, *device_,
constant_descriptor_pool_);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyDescriptorSetLayout,
device,
constant_descriptor_set_layout_);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyDescriptorPool, device,
constant_descriptor_pool_);
}
void BufferCache::Shutdown() {
@@ -319,9 +344,10 @@ void BufferCache::Shutdown() {
FreeVertexDescriptorPool();
transient_buffer_->Shutdown();
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
ui::vulkan::DestroyAndNullHandle(dfn.vkFreeMemory, *device_,
gpu_memory_pool_);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkFreeMemory, device,
gpu_memory_pool_);
}
std::pair<VkDeviceSize, VkDeviceSize> BufferCache::UploadConstantRegisters(
@@ -368,7 +394,7 @@ std::pair<VkDeviceSize, VkDeviceSize> BufferCache::UploadConstantRegisters(
offset,
kConstantRegisterUniformRange,
};
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
@@ -484,7 +510,7 @@ std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadIndexBuffer(
offset,
source_length,
};
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, 0, nullptr, 1,
&barrier, 0, nullptr);
@@ -552,7 +578,7 @@ std::pair<VkBuffer, VkDeviceSize> BufferCache::UploadVertexBuffer(
offset,
upload_size,
};
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr,
1, &barrier, 0, nullptr);
@@ -697,8 +723,9 @@ VkDescriptorSet BufferCache::PrepareVertexSet(
};
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
dfn.vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, nullptr);
vertex_sets_[hash] = set;
return set;
}
@@ -771,7 +798,8 @@ void BufferCache::CacheTransientData(uint32_t guest_address,
}
void BufferCache::Flush(VkCommandBuffer command_buffer) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
// If we are flushing a big enough chunk queue up an event.
// We don't want to do this for everything but often enough so that we won't
@@ -790,7 +818,7 @@ void BufferCache::Flush(VkCommandBuffer command_buffer) {
dirty_range.memory = transient_buffer_->gpu_memory();
dirty_range.offset = 0;
dirty_range.size = transient_buffer_->capacity();
dfn.vkFlushMappedMemoryRanges(*device_, 1, &dirty_range);
dfn.vkFlushMappedMemoryRanges(device, 1, &dirty_range);
}
void BufferCache::InvalidateCache() {

View File

@@ -17,10 +17,8 @@
#include "xenia/memory.h"
#include "xenia/ui/vulkan/circular_buffer.h"
#include "xenia/ui/vulkan/fenced_pools.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "third_party/vulkan/vk_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include <map>
#include <unordered_map>
@@ -35,7 +33,7 @@ namespace vulkan {
class BufferCache {
public:
BufferCache(RegisterFile* register_file, Memory* memory,
ui::vulkan::VulkanDevice* device, size_t capacity);
const ui::vulkan::VulkanProvider& provider, size_t capacity);
~BufferCache();
VkResult Initialize();
@@ -147,7 +145,7 @@ class BufferCache {
RegisterFile* register_file_ = nullptr;
Memory* memory_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
const ui::vulkan::VulkanProvider& provider_;
VkDeviceMemory gpu_memory_pool_ = nullptr;
VmaAllocator mem_allocator_ = nullptr;

View File

@@ -16,6 +16,7 @@
#include "xenia/base/xxhash.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_util.h"
#include <cinttypes>
#include <string>
@@ -24,18 +25,18 @@ namespace xe {
namespace gpu {
namespace vulkan {
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
// Generated with `xenia-build genspirv`.
#include "xenia/gpu/vulkan/shaders/bin/dummy_frag.h"
#include "xenia/gpu/vulkan/shaders/bin/line_quad_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bin/point_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bin/quad_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bin/rect_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/dummy_frag.h"
#include "xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/line_quad_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/point_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/quad_list_geom.h"
#include "xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/rect_list_geom.h"
PipelineCache::PipelineCache(RegisterFile* register_file,
ui::vulkan::VulkanDevice* device)
: register_file_(register_file), device_(device) {
const ui::vulkan::VulkanProvider& provider)
: register_file_(register_file), provider_(provider) {
shader_translator_.reset(new SpirvShaderTranslator());
}
@@ -45,7 +46,8 @@ VkResult PipelineCache::Initialize(
VkDescriptorSetLayout uniform_descriptor_set_layout,
VkDescriptorSetLayout texture_descriptor_set_layout,
VkDescriptorSetLayout vertex_descriptor_set_layout) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status;
// Initialize the shared driver pipeline cache.
@@ -58,7 +60,7 @@ VkResult PipelineCache::Initialize(
pipeline_cache_info.flags = 0;
pipeline_cache_info.initialDataSize = 0;
pipeline_cache_info.pInitialData = nullptr;
status = dfn.vkCreatePipelineCache(*device_, &pipeline_cache_info, nullptr,
status = dfn.vkCreatePipelineCache(device, &pipeline_cache_info, nullptr,
&pipeline_cache_);
if (status != VK_SUCCESS) {
return status;
@@ -96,7 +98,7 @@ VkResult PipelineCache::Initialize(
pipeline_layout_info.pushConstantRangeCount =
static_cast<uint32_t>(xe::countof(push_constant_ranges));
pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
status = dfn.vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr,
status = dfn.vkCreatePipelineLayout(device, &pipeline_layout_info, nullptr,
&pipeline_layout_);
if (status != VK_SUCCESS) {
return status;
@@ -113,58 +115,57 @@ VkResult PipelineCache::Initialize(
static_cast<uint32_t>(sizeof(line_quad_list_geom));
shader_module_info.pCode =
reinterpret_cast<const uint32_t*>(line_quad_list_geom);
status = dfn.vkCreateShaderModule(*device_, &shader_module_info, nullptr,
status = dfn.vkCreateShaderModule(device, &shader_module_info, nullptr,
&geometry_shaders_.line_quad_list);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(uint64_t(geometry_shaders_.line_quad_list),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
"S(g): Line Quad List");
provider_.SetDeviceObjectName(VK_OBJECT_TYPE_SHADER_MODULE,
uint64_t(geometry_shaders_.line_quad_list),
"S(g): Line Quad List");
shader_module_info.codeSize = static_cast<uint32_t>(sizeof(point_list_geom));
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(point_list_geom);
status = dfn.vkCreateShaderModule(*device_, &shader_module_info, nullptr,
status = dfn.vkCreateShaderModule(device, &shader_module_info, nullptr,
&geometry_shaders_.point_list);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(uint64_t(geometry_shaders_.point_list),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
"S(g): Point List");
provider_.SetDeviceObjectName(VK_OBJECT_TYPE_SHADER_MODULE,
uint64_t(geometry_shaders_.point_list),
"S(g): Point List");
shader_module_info.codeSize = static_cast<uint32_t>(sizeof(quad_list_geom));
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(quad_list_geom);
status = dfn.vkCreateShaderModule(*device_, &shader_module_info, nullptr,
status = dfn.vkCreateShaderModule(device, &shader_module_info, nullptr,
&geometry_shaders_.quad_list);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(uint64_t(geometry_shaders_.quad_list),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
"S(g): Quad List");
provider_.SetDeviceObjectName(VK_OBJECT_TYPE_SHADER_MODULE,
uint64_t(geometry_shaders_.quad_list),
"S(g): Quad List");
shader_module_info.codeSize = static_cast<uint32_t>(sizeof(rect_list_geom));
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(rect_list_geom);
status = dfn.vkCreateShaderModule(*device_, &shader_module_info, nullptr,
status = dfn.vkCreateShaderModule(device, &shader_module_info, nullptr,
&geometry_shaders_.rect_list);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(uint64_t(geometry_shaders_.rect_list),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
"S(g): Rect List");
provider_.SetDeviceObjectName(VK_OBJECT_TYPE_SHADER_MODULE,
uint64_t(geometry_shaders_.rect_list),
"S(g): Rect List");
shader_module_info.codeSize = static_cast<uint32_t>(sizeof(dummy_frag));
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(dummy_frag);
status = dfn.vkCreateShaderModule(*device_, &shader_module_info, nullptr,
status = dfn.vkCreateShaderModule(device, &shader_module_info, nullptr,
&dummy_pixel_shader_);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(uint64_t(dummy_pixel_shader_),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
"S(p): Dummy");
provider_.SetDeviceObjectName(VK_OBJECT_TYPE_SHADER_MODULE,
uint64_t(dummy_pixel_shader_), "S(g): Dummy");
return VK_SUCCESS;
}
@@ -172,37 +173,38 @@ VkResult PipelineCache::Initialize(
void PipelineCache::Shutdown() {
ClearCache();
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
// Destroy geometry shaders.
if (geometry_shaders_.line_quad_list) {
dfn.vkDestroyShaderModule(*device_, geometry_shaders_.line_quad_list,
dfn.vkDestroyShaderModule(device, geometry_shaders_.line_quad_list,
nullptr);
geometry_shaders_.line_quad_list = nullptr;
}
if (geometry_shaders_.point_list) {
dfn.vkDestroyShaderModule(*device_, geometry_shaders_.point_list, nullptr);
dfn.vkDestroyShaderModule(device, geometry_shaders_.point_list, nullptr);
geometry_shaders_.point_list = nullptr;
}
if (geometry_shaders_.quad_list) {
dfn.vkDestroyShaderModule(*device_, geometry_shaders_.quad_list, nullptr);
dfn.vkDestroyShaderModule(device, geometry_shaders_.quad_list, nullptr);
geometry_shaders_.quad_list = nullptr;
}
if (geometry_shaders_.rect_list) {
dfn.vkDestroyShaderModule(*device_, geometry_shaders_.rect_list, nullptr);
dfn.vkDestroyShaderModule(device, geometry_shaders_.rect_list, nullptr);
geometry_shaders_.rect_list = nullptr;
}
if (dummy_pixel_shader_) {
dfn.vkDestroyShaderModule(*device_, dummy_pixel_shader_, nullptr);
dfn.vkDestroyShaderModule(device, dummy_pixel_shader_, nullptr);
dummy_pixel_shader_ = nullptr;
}
if (pipeline_layout_) {
dfn.vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr);
dfn.vkDestroyPipelineLayout(device, pipeline_layout_, nullptr);
pipeline_layout_ = nullptr;
}
if (pipeline_cache_) {
dfn.vkDestroyPipelineCache(*device_, pipeline_cache_, nullptr);
dfn.vkDestroyPipelineCache(device, pipeline_cache_, nullptr);
pipeline_cache_ = nullptr;
}
}
@@ -223,7 +225,7 @@ VulkanShader* PipelineCache::LoadShader(xenos::ShaderType shader_type,
// Always create the shader and stash it away.
// We need to track it even if it fails translation so we know not to try
// again.
VulkanShader* shader = new VulkanShader(device_, shader_type, data_hash,
VulkanShader* shader = new VulkanShader(provider_, shader_type, data_hash,
host_address, dword_count);
shader_map_.insert({data_hash, shader});
@@ -278,10 +280,11 @@ PipelineCache::UpdateStatus PipelineCache::ConfigurePipeline(
}
void PipelineCache::ClearCache() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
// Destroy all pipelines.
for (auto it : cached_pipelines_) {
dfn.vkDestroyPipeline(*device_, it.second, nullptr);
dfn.vkDestroyPipeline(device, it.second, nullptr);
}
cached_pipelines_.clear();
COUNT_profile_set("gpu/pipeline_cache/pipelines", 0);
@@ -343,9 +346,10 @@ VkPipeline PipelineCache::GetPipeline(const RenderState* render_state,
pipeline_info.basePipelineHandle = nullptr;
pipeline_info.basePipelineIndex = -1;
VkPipeline pipeline = nullptr;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
auto result = dfn.vkCreateGraphicsPipelines(
*device_, pipeline_cache_, 1, &pipeline_info, nullptr, &pipeline);
device, pipeline_cache_, 1, &pipeline_info, nullptr, &pipeline);
if (result != VK_SUCCESS) {
XELOGE("vkCreateGraphicsPipelines failed with code {}", result);
assert_always();
@@ -354,9 +358,10 @@ VkPipeline PipelineCache::GetPipeline(const RenderState* render_state,
// Dump shader disassembly.
if (cvars::vulkan_dump_disasm) {
if (device_->HasEnabledExtension(VK_AMD_SHADER_INFO_EXTENSION_NAME)) {
if (provider_.device_extensions().amd_shader_info) {
DumpShaderDisasmAMD(pipeline);
} else if (device_->device_info().properties.vendorID == 0x10DE) {
} else if (provider_.device_properties().vendorID ==
uint32_t(ui::GraphicsProvider::GpuVendorID::kNvidia)) {
// NVIDIA cards
DumpShaderDisasmNV(pipeline_info);
}
@@ -421,7 +426,8 @@ static void DumpShaderStatisticsAMD(const VkShaderStatisticsInfoAMD& stats) {
}
void PipelineCache::DumpShaderDisasmAMD(VkPipeline pipeline) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
size_t data_size = 0;
@@ -429,9 +435,9 @@ void PipelineCache::DumpShaderDisasmAMD(VkPipeline pipeline) {
data_size = sizeof(stats);
// Vertex shader
status = dfn.vkGetShaderInfoAMD(
*device_, pipeline, VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_INFO_TYPE_STATISTICS_AMD, &data_size, &stats);
status = dfn.vkGetShaderInfoAMD(device, pipeline, VK_SHADER_STAGE_VERTEX_BIT,
VK_SHADER_INFO_TYPE_STATISTICS_AMD,
&data_size, &stats);
if (status == VK_SUCCESS) {
XELOGI("AMD Vertex Shader Statistics:");
DumpShaderStatisticsAMD(stats);
@@ -439,7 +445,7 @@ void PipelineCache::DumpShaderDisasmAMD(VkPipeline pipeline) {
// Fragment shader
status = dfn.vkGetShaderInfoAMD(
*device_, pipeline, VK_SHADER_STAGE_FRAGMENT_BIT,
device, pipeline, VK_SHADER_STAGE_FRAGMENT_BIT,
VK_SHADER_INFO_TYPE_STATISTICS_AMD, &data_size, &stats);
if (status == VK_SUCCESS) {
XELOGI("AMD Fragment Shader Statistics:");
@@ -455,7 +461,8 @@ void PipelineCache::DumpShaderDisasmNV(
// This code is super ugly. Update this when NVidia includes an official
// way to dump shader disassembly.
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkPipelineCacheCreateInfo pipeline_cache_info;
VkPipelineCache dummy_pipeline_cache;
@@ -464,23 +471,23 @@ void PipelineCache::DumpShaderDisasmNV(
pipeline_cache_info.flags = 0;
pipeline_cache_info.initialDataSize = 0;
pipeline_cache_info.pInitialData = nullptr;
auto status = dfn.vkCreatePipelineCache(*device_, &pipeline_cache_info,
nullptr, &dummy_pipeline_cache);
auto status = dfn.vkCreatePipelineCache(device, &pipeline_cache_info, nullptr,
&dummy_pipeline_cache);
CheckResult(status, "vkCreatePipelineCache");
// Create a pipeline on the dummy cache and dump it.
VkPipeline dummy_pipeline;
status =
dfn.vkCreateGraphicsPipelines(*device_, dummy_pipeline_cache, 1,
dfn.vkCreateGraphicsPipelines(device, dummy_pipeline_cache, 1,
&pipeline_info, nullptr, &dummy_pipeline);
std::vector<uint8_t> pipeline_data;
size_t data_size = 0;
status = dfn.vkGetPipelineCacheData(*device_, dummy_pipeline_cache,
&data_size, nullptr);
status = dfn.vkGetPipelineCacheData(device, dummy_pipeline_cache, &data_size,
nullptr);
if (status == VK_SUCCESS) {
pipeline_data.resize(data_size);
dfn.vkGetPipelineCacheData(*device_, dummy_pipeline_cache, &data_size,
dfn.vkGetPipelineCacheData(device, dummy_pipeline_cache, &data_size,
pipeline_data.data());
// Scan the data for the disassembly.
@@ -537,8 +544,8 @@ void PipelineCache::DumpShaderDisasmNV(
disasm_fp);
}
dfn.vkDestroyPipeline(*device_, dummy_pipeline, nullptr);
dfn.vkDestroyPipelineCache(*device_, dummy_pipeline_cache, nullptr);
dfn.vkDestroyPipeline(device, dummy_pipeline, nullptr);
dfn.vkDestroyPipelineCache(device, dummy_pipeline_cache, nullptr);
}
VkShaderModule PipelineCache::GetGeometryShader(
@@ -582,7 +589,7 @@ bool PipelineCache::SetDynamicState(VkCommandBuffer command_buffer,
SCOPE_profile_cpu_f("gpu");
#endif // FINE_GRAINED_DRAW_SCOPES
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
auto& regs = set_dynamic_state_registers_;
bool window_offset_dirty = SetShadowRegister(&regs.pa_sc_window_offset,

View File

@@ -20,8 +20,7 @@
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/spirv/spirv_disassembler.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {
@@ -38,7 +37,8 @@ class PipelineCache {
kError,
};
PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
PipelineCache(RegisterFile* register_file,
const ui::vulkan::VulkanProvider& provider);
~PipelineCache();
VkResult Initialize(VkDescriptorSetLayout uniform_descriptor_set_layout,
@@ -90,7 +90,7 @@ class PipelineCache {
bool is_line_mode);
RegisterFile* register_file_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
const ui::vulkan::VulkanProvider& provider_;
// Temporary storage for AnalyzeUcode calls.
StringBuffer ucode_disasm_buffer_;

View File

@@ -19,13 +19,14 @@
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/registers.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
namespace gpu {
namespace vulkan {
using namespace xe::gpu::xenos;
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
constexpr uint32_t kEdramBufferCapacity = 10 * 1024 * 1024;
@@ -105,7 +106,7 @@ class CachedFramebuffer {
// Associated render pass
VkRenderPass render_pass = nullptr;
CachedFramebuffer(const ui::vulkan::VulkanDevice& device,
CachedFramebuffer(const ui::vulkan::VulkanProvider& provider,
VkRenderPass render_pass, uint32_t surface_width,
uint32_t surface_height,
CachedTileView* target_color_attachments[4],
@@ -117,7 +118,7 @@ class CachedFramebuffer {
bool IsCompatible(const RenderConfiguration& desired_config) const;
private:
const ui::vulkan::VulkanDevice& device_;
const ui::vulkan::VulkanProvider& provider_;
};
// Cached render passes based on register states.
@@ -134,7 +135,7 @@ class CachedRenderPass {
// Cache of framebuffers for the various tile attachments.
std::vector<CachedFramebuffer*> cached_framebuffers;
CachedRenderPass(const ui::vulkan::VulkanDevice& device,
CachedRenderPass(const ui::vulkan::VulkanProvider& provider,
const RenderConfiguration& desired_config);
~CachedRenderPass();
@@ -143,28 +144,30 @@ class CachedRenderPass {
bool IsCompatible(const RenderConfiguration& desired_config) const;
private:
const ui::vulkan::VulkanDevice& device_;
const ui::vulkan::VulkanProvider& provider_;
};
CachedTileView::CachedTileView(ui::vulkan::VulkanDevice* device,
CachedTileView::CachedTileView(const ui::vulkan::VulkanProvider& provider,
VkDeviceMemory edram_memory,
TileViewKey view_key)
: device_(device), key(std::move(view_key)) {}
: provider_(provider), key(std::move(view_key)) {}
CachedTileView::~CachedTileView() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyImageView, *device_,
image_view);
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyImageView, *device_,
image_view_depth);
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyImageView, *device_,
image_view_stencil);
ui::vulkan::DestroyAndNullHandle(dfn.vkDestroyImage, *device_, image);
ui::vulkan::DestroyAndNullHandle(dfn.vkFreeMemory, *device_, memory);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyImageView, device,
image_view);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyImageView, device,
image_view_depth);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyImageView, device,
image_view_stencil);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyImage, device, image);
ui::vulkan::util::DestroyAndNullHandle(dfn.vkFreeMemory, device, memory);
}
VkResult CachedTileView::Initialize(VkCommandBuffer command_buffer) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
// Map format to Vulkan.
@@ -237,26 +240,40 @@ VkResult CachedTileView::Initialize(VkCommandBuffer command_buffer) {
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = nullptr;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
status = dfn.vkCreateImage(*device_, &image_info, nullptr, &image);
status = dfn.vkCreateImage(device, &image_info, nullptr, &image);
if (status != VK_SUCCESS) {
return status;
}
device_->DbgSetObjectName(
reinterpret_cast<uint64_t>(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
provider_.SetDeviceObjectName(
VK_OBJECT_TYPE_IMAGE, uint64_t(image),
fmt::format("RT(d): 0x{:08X} 0x{:08X}({}) 0x{:08X}({}) {} {} {}",
uint32_t(key.tile_offset), uint32_t(key.tile_width),
uint32_t(key.tile_width), uint32_t(key.tile_height),
uint32_t(key.tile_height), uint32_t(key.color_or_depth),
uint32_t(key.msaa_samples), uint32_t(key.edram_format)));
uint32_t(key.msaa_samples), uint32_t(key.edram_format))
.c_str());
VkMemoryRequirements memory_requirements;
dfn.vkGetImageMemoryRequirements(*device_, image, &memory_requirements);
dfn.vkGetImageMemoryRequirements(device, image, &memory_requirements);
// Bind to a newly allocated chunk.
// TODO: Alias from a really big buffer?
memory = device_->AllocateMemory(memory_requirements, 0);
status = dfn.vkBindImageMemory(*device_, image, memory, 0);
VkMemoryAllocateInfo memory_allocate_info;
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memory_allocate_info.pNext = nullptr;
memory_allocate_info.allocationSize = memory_requirements.size;
if (!xe::bit_scan_forward(memory_requirements.memoryTypeBits &
provider_.memory_types_device_local(),
&memory_allocate_info.memoryTypeIndex)) {
return VK_ERROR_INITIALIZATION_FAILED;
}
status =
dfn.vkAllocateMemory(device, &memory_allocate_info, nullptr, &memory);
if (status != VK_SUCCESS) {
return status;
}
status = dfn.vkBindImageMemory(device, image, memory, 0);
if (status != VK_SUCCESS) {
return status;
}
@@ -284,7 +301,7 @@ VkResult CachedTileView::Initialize(VkCommandBuffer command_buffer) {
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
}
status =
dfn.vkCreateImageView(*device_, &image_view_info, nullptr, &image_view);
dfn.vkCreateImageView(device, &image_view_info, nullptr, &image_view);
if (status != VK_SUCCESS) {
return status;
}
@@ -292,14 +309,14 @@ VkResult CachedTileView::Initialize(VkCommandBuffer command_buffer) {
// Create separate depth/stencil views.
if (key.color_or_depth == 0) {
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
status = dfn.vkCreateImageView(*device_, &image_view_info, nullptr,
status = dfn.vkCreateImageView(device, &image_view_info, nullptr,
&image_view_depth);
if (status != VK_SUCCESS) {
return status;
}
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
status = dfn.vkCreateImageView(*device_, &image_view_info, nullptr,
status = dfn.vkCreateImageView(device, &image_view_info, nullptr,
&image_view_stencil);
if (status != VK_SUCCESS) {
return status;
@@ -338,11 +355,11 @@ VkResult CachedTileView::Initialize(VkCommandBuffer command_buffer) {
}
CachedFramebuffer::CachedFramebuffer(
const ui::vulkan::VulkanDevice& device, VkRenderPass render_pass,
const ui::vulkan::VulkanProvider& provider, VkRenderPass render_pass,
uint32_t surface_width, uint32_t surface_height,
CachedTileView* target_color_attachments[4],
CachedTileView* target_depth_stencil_attachment)
: device_(device),
: provider_(provider),
width(surface_width),
height(surface_height),
depth_stencil_attachment(target_depth_stencil_attachment),
@@ -354,8 +371,9 @@ CachedFramebuffer::CachedFramebuffer(
CachedFramebuffer::~CachedFramebuffer() {
if (handle != VK_NULL_HANDLE) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_.dfn();
dfn.vkDestroyFramebuffer(device_, handle, nullptr);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
dfn.vkDestroyFramebuffer(device, handle, nullptr);
}
}
@@ -381,8 +399,9 @@ VkResult CachedFramebuffer::Initialize() {
framebuffer_info.width = width;
framebuffer_info.height = height;
framebuffer_info.layers = 1;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_.dfn();
return dfn.vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &handle);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
return dfn.vkCreateFramebuffer(device, &framebuffer_info, nullptr, &handle);
}
bool CachedFramebuffer::IsCompatible(
@@ -427,9 +446,9 @@ bool CachedFramebuffer::IsCompatible(
return true;
}
CachedRenderPass::CachedRenderPass(const ui::vulkan::VulkanDevice& device,
CachedRenderPass::CachedRenderPass(const ui::vulkan::VulkanProvider& provider,
const RenderConfiguration& desired_config)
: device_(device) {
: provider_(provider) {
std::memcpy(&config, &desired_config, sizeof(config));
}
@@ -440,8 +459,9 @@ CachedRenderPass::~CachedRenderPass() {
cached_framebuffers.clear();
if (handle != VK_NULL_HANDLE) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_.dfn();
dfn.vkDestroyRenderPass(device_, handle, nullptr);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
dfn.vkDestroyRenderPass(device, handle, nullptr);
}
}
@@ -553,8 +573,9 @@ VkResult CachedRenderPass::Initialize() {
render_pass_info.dependencyCount = 1;
render_pass_info.pDependencies = dependencies;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_.dfn();
return dfn.vkCreateRenderPass(device_, &render_pass_info, nullptr, &handle);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
return dfn.vkCreateRenderPass(device, &render_pass_info, nullptr, &handle);
}
bool CachedRenderPass::IsCompatible(
@@ -577,13 +598,14 @@ bool CachedRenderPass::IsCompatible(
}
RenderCache::RenderCache(RegisterFile* register_file,
ui::vulkan::VulkanDevice* device)
: register_file_(register_file), device_(device) {}
const ui::vulkan::VulkanProvider& provider)
: register_file_(register_file), provider_(provider) {}
RenderCache::~RenderCache() { Shutdown(); }
VkResult RenderCache::Initialize() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
// Create the buffer we'll bind to our memory.
@@ -597,7 +619,7 @@ VkResult RenderCache::Initialize() {
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
buffer_info.queueFamilyIndexCount = 0;
buffer_info.pQueueFamilyIndices = nullptr;
status = dfn.vkCreateBuffer(*device_, &buffer_info, nullptr, &edram_buffer_);
status = dfn.vkCreateBuffer(device, &buffer_info, nullptr, &edram_buffer_);
CheckResult(status, "vkCreateBuffer");
if (status != VK_SUCCESS) {
return status;
@@ -606,20 +628,29 @@ VkResult RenderCache::Initialize() {
// Query requirements for the buffer.
// It should be 1:1.
VkMemoryRequirements buffer_requirements;
dfn.vkGetBufferMemoryRequirements(*device_, edram_buffer_,
dfn.vkGetBufferMemoryRequirements(device, edram_buffer_,
&buffer_requirements);
assert_true(buffer_requirements.size == kEdramBufferCapacity);
// Allocate EDRAM memory.
// TODO(benvanik): do we need it host visible?
edram_memory_ = device_->AllocateMemory(buffer_requirements);
assert_not_null(edram_memory_);
if (!edram_memory_) {
VkMemoryAllocateInfo buffer_allocate_info;
buffer_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
buffer_allocate_info.pNext = nullptr;
buffer_allocate_info.allocationSize = buffer_requirements.size;
buffer_allocate_info.memoryTypeIndex = ui::vulkan::util::ChooseHostMemoryType(
provider_, buffer_requirements.memoryTypeBits, false);
if (buffer_allocate_info.memoryTypeIndex == UINT32_MAX) {
return VK_ERROR_INITIALIZATION_FAILED;
}
status = dfn.vkAllocateMemory(device, &buffer_allocate_info, nullptr,
&edram_memory_);
if (status != VK_SUCCESS) {
return status;
}
// Bind buffer to map our entire memory.
status = dfn.vkBindBufferMemory(*device_, edram_buffer_, edram_memory_, 0);
status = dfn.vkBindBufferMemory(device, edram_buffer_, edram_memory_, 0);
CheckResult(status, "vkBindBufferMemory");
if (status != VK_SUCCESS) {
return status;
@@ -628,16 +659,15 @@ VkResult RenderCache::Initialize() {
if (status == VK_SUCCESS) {
// For debugging, upload a grid into the EDRAM buffer.
uint32_t* gpu_data = nullptr;
status =
dfn.vkMapMemory(*device_, edram_memory_, 0, buffer_requirements.size, 0,
reinterpret_cast<void**>(&gpu_data));
status = dfn.vkMapMemory(device, edram_memory_, 0, buffer_requirements.size,
0, reinterpret_cast<void**>(&gpu_data));
if (status == VK_SUCCESS) {
for (int i = 0; i < kEdramBufferCapacity / 4; i++) {
gpu_data[i] = (i % 8) >= 4 ? 0xFF0000FF : 0xFFFFFFFF;
}
dfn.vkUnmapMemory(*device_, edram_memory_);
dfn.vkUnmapMemory(device, edram_memory_);
}
}
@@ -647,7 +677,8 @@ VkResult RenderCache::Initialize() {
void RenderCache::Shutdown() {
// TODO(benvanik): wait for idle.
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
// Dispose all render passes (and their framebuffers).
for (auto render_pass : cached_render_passes_) {
@@ -663,11 +694,11 @@ void RenderCache::Shutdown() {
// Release underlying EDRAM memory.
if (edram_buffer_) {
dfn.vkDestroyBuffer(*device_, edram_buffer_, nullptr);
dfn.vkDestroyBuffer(device, edram_buffer_, nullptr);
edram_buffer_ = nullptr;
}
if (edram_memory_) {
dfn.vkFreeMemory(*device_, edram_memory_, nullptr);
dfn.vkFreeMemory(device, edram_memory_, nullptr);
edram_memory_ = nullptr;
}
}
@@ -803,7 +834,7 @@ const RenderState* RenderCache::BeginRenderPass(VkCommandBuffer command_buffer,
render_pass_begin_info.pClearValues = nullptr;
// Begin the render pass.
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
VK_SUBPASS_CONTENTS_INLINE);
@@ -891,11 +922,10 @@ bool RenderCache::ConfigureRenderPass(VkCommandBuffer command_buffer,
// If no render pass was found in the cache create a new one.
if (!render_pass) {
render_pass = new CachedRenderPass(*device_, *config);
render_pass = new CachedRenderPass(provider_, *config);
VkResult status = render_pass->Initialize();
if (status != VK_SUCCESS) {
XELOGE("{}: Failed to create render pass, status {}", __func__,
ui::vulkan::to_string(status));
XELOGE("{}: Failed to create render pass", __func__);
delete render_pass;
return false;
}
@@ -971,12 +1001,11 @@ bool RenderCache::ConfigureRenderPass(VkCommandBuffer command_buffer,
surface_pitch_px = std::min(surface_pitch_px, 2560u);
surface_height_px = std::min(surface_height_px, 2560u);
framebuffer = new CachedFramebuffer(
*device_, render_pass->handle, surface_pitch_px, surface_height_px,
provider_, render_pass->handle, surface_pitch_px, surface_height_px,
target_color_attachments, target_depth_stencil_attachment);
VkResult status = framebuffer->Initialize();
if (status != VK_SUCCESS) {
XELOGE("{}: Failed to create framebuffer, status {}", __func__,
ui::vulkan::to_string(status));
XELOGE("{}: Failed to create framebuffer", __func__);
delete framebuffer;
return false;
}
@@ -1025,11 +1054,10 @@ CachedTileView* RenderCache::FindOrCreateTileView(
}
// Create a new tile and add to the cache.
tile_view = new CachedTileView(device_, edram_memory_, view_key);
tile_view = new CachedTileView(provider_, edram_memory_, view_key);
VkResult status = tile_view->Initialize(command_buffer);
if (status != VK_SUCCESS) {
XELOGE("{}: Failed to create tile view, status {}", __func__,
ui::vulkan::to_string(status));
XELOGE("{}: Failed to create tile view", __func__);
delete tile_view;
return nullptr;
@@ -1042,7 +1070,7 @@ CachedTileView* RenderCache::FindOrCreateTileView(
void RenderCache::UpdateTileView(VkCommandBuffer command_buffer,
CachedTileView* view, bool load,
bool insert_barrier) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
uint32_t tile_width =
view->key.msaa_samples == uint16_t(xenos::MsaaSamples::k4X) ? 40 : 80;
@@ -1111,7 +1139,7 @@ void RenderCache::EndRenderPass() {
assert_not_null(current_command_buffer_);
// End the render pass.
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdEndRenderPass(current_command_buffer_);
// Copy all render targets back into our EDRAM buffer.
@@ -1165,7 +1193,7 @@ void RenderCache::RawCopyToImage(VkCommandBuffer command_buffer,
VkImageLayout image_layout,
bool color_or_depth, VkOffset3D offset,
VkExtent3D extents) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
// Transition the texture into a transfer destination layout.
VkImageMemoryBarrier image_barrier;
@@ -1239,7 +1267,7 @@ void RenderCache::BlitToImage(VkCommandBuffer command_buffer,
bool color_or_depth, uint32_t format,
VkFilter filter, VkOffset3D offset,
VkExtent3D extents) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
if (color_or_depth) {
// Adjust similar formats for easier matching.
@@ -1372,7 +1400,7 @@ void RenderCache::ClearEDRAMColor(VkCommandBuffer command_buffer,
std::memcpy(clear_value.float32, color, sizeof(float) * 4);
// Issue a clear command
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdClearColorImage(command_buffer, tile_view->image,
VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1, &range);
@@ -1412,7 +1440,7 @@ void RenderCache::ClearEDRAMDepthStencil(VkCommandBuffer command_buffer,
clear_value.stencil = stencil;
// Issue a clear command
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdClearDepthStencilImage(command_buffer, tile_view->image,
VK_IMAGE_LAYOUT_GENERAL, &clear_value, 1,
&range);
@@ -1422,7 +1450,7 @@ void RenderCache::ClearEDRAMDepthStencil(VkCommandBuffer command_buffer,
}
void RenderCache::FillEDRAM(VkCommandBuffer command_buffer, uint32_t value) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
dfn.vkCmdFillBuffer(command_buffer, edram_buffer_, 0, kEdramBufferCapacity,
value);
}

View File

@@ -16,8 +16,7 @@
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {
@@ -68,8 +67,8 @@ class CachedTileView {
// (if a depth view) Image view of stencil aspect
VkImageView image_view_stencil = nullptr;
CachedTileView(ui::vulkan::VulkanDevice* device, VkDeviceMemory edram_memory,
TileViewKey view_key);
CachedTileView(const ui::vulkan::VulkanProvider& provider,
VkDeviceMemory edram_memory, TileViewKey view_key);
~CachedTileView();
VkResult Initialize(VkCommandBuffer command_buffer);
@@ -89,7 +88,7 @@ class CachedTileView {
}
private:
ui::vulkan::VulkanDevice* device_ = nullptr;
const ui::vulkan::VulkanProvider& provider_;
};
// Parsed render configuration from the current render state.
@@ -274,7 +273,8 @@ struct RenderState {
// must check for overlap then compute the offset (in both X and Y).
class RenderCache {
public:
RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
RenderCache(RegisterFile* register_file,
const ui::vulkan::VulkanProvider& provider);
~RenderCache();
VkResult Initialize();
@@ -358,7 +358,7 @@ class RenderCache {
CachedFramebuffer** out_framebuffer);
RegisterFile* register_file_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
const ui::vulkan::VulkanProvider& provider_;
// Entire 10MiB of EDRAM.
VkDeviceMemory edram_memory_ = nullptr;

View File

@@ -0,0 +1,2 @@
DisableFormat: true
SortIncludes: false

View File

@@ -1,7 +1,7 @@
// generated from `xb genspirv`
// source: dummy.frag
const uint8_t dummy_frag[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00,
0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x2B, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,

Binary file not shown.

View File

@@ -1,6 +1,6 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 50
; Schema: 0
OpCapability Shader

View File

@@ -1,7 +1,7 @@
// generated from `xb genspirv`
// source: line_quad_list.geom
const uint8_t line_quad_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00,
0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,

View File

@@ -1,6 +1,6 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 83
; Schema: 0
OpCapability Geometry

View File

@@ -1,7 +1,7 @@
// generated from `xb genspirv`
// source: point_list.geom
const uint8_t point_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00,
0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,
0x47, 0x4C, 0x53, 0x4C, 0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30,

View File

@@ -1,6 +1,6 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 118
; Schema: 0
OpCapability Geometry

View File

@@ -1,7 +1,7 @@
// generated from `xb genspirv`
// source: quad_list.geom
const uint8_t quad_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00,
0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,

Binary file not shown.

View File

@@ -1,6 +1,6 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 76
; Schema: 0
OpCapability Geometry

View File

@@ -1,8 +1,8 @@
// generated from `xb genspirv`
// source: rect_list.geom
const uint8_t rect_list_geom[] = {
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x08, 0x00,
0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x08, 0x00,
0x2A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,
0x02, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x18, 0x00, 0x00, 0x00,
0x0B, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x53, 0x4C,
0x2E, 0x73, 0x74, 0x64, 0x2E, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00,
@@ -124,7 +124,7 @@ const uint8_t rect_list_geom[] = {
0x20, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x04, 0x00, 0x10, 0x01, 0x00, 0x00,
0x11, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x05, 0x00,
0x07, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00,
0x2F, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00,
@@ -143,14 +143,14 @@ const uint8_t rect_list_geom[] = {
0x4F, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x16, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00,
0xBC, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1A, 0x01, 0x00, 0x00,
0x17, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x9B, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0x1A, 0x01, 0x00, 0x00,
0x17, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00,
0xBC, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00,
0x18, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x9B, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00,
0xA8, 0x00, 0x04, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,
0x1B, 0x01, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x1C, 0x01, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00, 0x3A, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00,
0x39, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x39, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
@@ -163,16 +163,16 @@ const uint8_t rect_list_geom[] = {
0x3E, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00,
0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
0x3E, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,
0x1F, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x00,
0xBC, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00,
0x20, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x9B, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00,
0x21, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00,
0xBC, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00,
0x22, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x9B, 0x00, 0x04, 0x00,
0x0A, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x3A, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x3A, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x47, 0x00, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x24, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x47, 0x00, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x26, 0x01, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0xF7, 0x00, 0x03, 0x00,
0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0x47, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
@@ -244,32 +244,32 @@ const uint8_t rect_list_geom[] = {
0x3E, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x99, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0x99, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00, 0x23, 0x00, 0x00, 0x00,
0x27, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0x29, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x05, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00,
0x0A, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00,
0x9F, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00, 0x9B, 0x00, 0x00, 0x00,
0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x00, 0x04, 0x00,
0xA0, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x31, 0x00, 0x00, 0x00, 0xA3, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x24, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x1C, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0xA3, 0x00, 0x00, 0x00,
0x7F, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00,
0xA4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00,
0xA7, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x27, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x29, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0xA8, 0x00, 0x00, 0x00, 0xA7, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
0x1C, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00,
0xA8, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00,
0xAB, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,
0x27, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x29, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0xAC, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00,
0x1C, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x00, 0x00,
0xAC, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x4F, 0x00, 0x00, 0x00,
0xAE, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00,
0xAE, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00,
0x3E, 0x00, 0x03, 0x00, 0xAE, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00,
0x80, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00,
0x27, 0x01, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x29, 0x01, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x99, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0x9B, 0x00, 0x00, 0x00,
0xDA, 0x00, 0x01, 0x00, 0xDB, 0x00, 0x01, 0x00, 0xF9, 0x00, 0x02, 0x00,
0x49, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xB1, 0x00, 0x00, 0x00,
@@ -341,32 +341,32 @@ const uint8_t rect_list_geom[] = {
0xED, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0xB7, 0x00, 0x00, 0x00,
0xC6, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x02, 0x00, 0xF3, 0x00, 0x00, 0x00,
0xF8, 0x00, 0x02, 0x00, 0xF3, 0x00, 0x00, 0x00, 0xF5, 0x00, 0x07, 0x00,
0x23, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x23, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0xB1, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00,
0xB1, 0x00, 0x05, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x00, 0x00,
0x26, 0x01, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00,
0x28, 0x01, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x04, 0x00,
0xF5, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFA, 0x00, 0x04, 0x00, 0xF9, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00,
0xF5, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00, 0xF4, 0x00, 0x00, 0x00,
0x41, 0x00, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00,
0x5B, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00,
0x5B, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00,
0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00,
0xFC, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x31, 0x00, 0x00, 0x00,
0xFF, 0x00, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x26, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x28, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x04, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x81, 0x00, 0x05, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00,
0xFD, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,
0x31, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x5B, 0x00, 0x00, 0x00,
0x25, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x25, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x3D, 0x00, 0x04, 0x00,
0x1C, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00,
0x81, 0x00, 0x05, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00,
0x02, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00,
0x4F, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00,
0x26, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x07, 0x01, 0x00, 0x00,
0x28, 0x01, 0x00, 0x00, 0x3E, 0x00, 0x03, 0x00, 0x07, 0x01, 0x00, 0x00,
0x06, 0x01, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00,
0x09, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0x09, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00,
0xF9, 0x00, 0x02, 0x00, 0xF3, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,
0xF5, 0x00, 0x00, 0x00, 0xDA, 0x00, 0x01, 0x00, 0xDB, 0x00, 0x01, 0x00,
0xF9, 0x00, 0x02, 0x00, 0x49, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x02, 0x00,

Binary file not shown.

View File

@@ -1,7 +1,7 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 296
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 298
; Schema: 0
OpCapability Geometry
OpCapability GeometryPointSize
@@ -84,7 +84,7 @@
%_in_point_size_unused = OpVariable %_ptr_Input__arr_float_uint_3 Input
%_ptr_Output_v2float = OpTypePointer Output %v2float
%_out_point_coord_unused = OpVariable %_ptr_Output_v2float Output
%293 = OpConstantComposite %v2float %float_0_00100000005 %float_0_00100000005
%295 = OpConstantComposite %v2float %float_0_00100000005 %float_0_00100000005
%main = OpFunction %void None %3
%5 = OpLabel
%40 = OpAccessChain %_ptr_Input_float %gl_in %int_2 %int_0 %uint_0
@@ -95,11 +95,11 @@
%50 = OpAccessChain %_ptr_Input_v4float %gl_in %int_0 %int_0
%51 = OpLoad %v4float %50
%52 = OpVectorShuffle %v2float %51 %51 0 1
%278 = OpFSub %v2float %52 %46
%279 = OpExtInst %v2float %1 FAbs %278
%282 = OpFOrdLessThanEqual %v2bool %279 %293
%283 = OpAll %bool %282
%56 = OpLogicalNot %bool %283
%279 = OpFSub %v2float %52 %46
%280 = OpExtInst %v2float %1 FAbs %279
%283 = OpFOrdLessThanEqual %v2bool %280 %295
%284 = OpAll %bool %283
%56 = OpLogicalNot %bool %284
OpSelectionMerge %58 None
OpBranchConditional %56 %57 %58
%57 = OpLabel
@@ -108,13 +108,13 @@
%61 = OpAccessChain %_ptr_Input_float %gl_in %int_2 %int_0 %uint_1
%62 = OpLoad %float %61
%63 = OpCompositeConstruct %v2float %60 %62
%287 = OpFSub %v2float %52 %63
%288 = OpExtInst %v2float %1 FAbs %287
%291 = OpFOrdLessThanEqual %v2bool %288 %293
%292 = OpAll %bool %291
%289 = OpFSub %v2float %52 %63
%290 = OpExtInst %v2float %1 FAbs %289
%293 = OpFOrdLessThanEqual %v2bool %290 %295
%294 = OpAll %bool %293
OpBranch %58
%58 = OpLabel
%71 = OpPhi %bool %283 %5 %292 %57
%71 = OpPhi %bool %284 %5 %294 %57
OpSelectionMerge %73 None
OpBranchConditional %71 %72 %177
%72 = OpLabel
@@ -171,23 +171,23 @@
OpStore %84 %107
OpBranch %153
%153 = OpLabel
%295 = OpPhi %int %int_0 %72 %176 %154
%160 = OpSLessThan %bool %295 %int_16
%297 = OpPhi %int %int_0 %72 %176 %154
%160 = OpSLessThan %bool %297 %int_16
OpLoopMerge %155 %154 None
OpBranchConditional %160 %154 %155
%154 = OpLabel
%163 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_0 %295
%163 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_0 %297
%164 = OpLoad %v4float %163
%165 = OpFNegate %v4float %164
%167 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_1 %295
%167 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_1 %297
%168 = OpLoad %v4float %167
%169 = OpFAdd %v4float %165 %168
%171 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_2 %295
%171 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_2 %297
%172 = OpLoad %v4float %171
%173 = OpFAdd %v4float %169 %172
%174 = OpAccessChain %_ptr_Output_v4float %out_interpolators %295
%174 = OpAccessChain %_ptr_Output_v4float %out_interpolators %297
OpStore %174 %173
%176 = OpIAdd %int %295 %int_1
%176 = OpIAdd %int %297 %int_1
OpBranch %153
%155 = OpLabel
OpEmitVertex
@@ -247,23 +247,23 @@
OpStore %183 %198
OpBranch %243
%243 = OpLabel
%294 = OpPhi %int %int_0 %177 %265 %244
%249 = OpSLessThan %bool %294 %int_16
%296 = OpPhi %int %int_0 %177 %265 %244
%249 = OpSLessThan %bool %296 %int_16
OpLoopMerge %245 %244 None
OpBranchConditional %249 %244 %245
%244 = OpLabel
%252 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_0 %294
%252 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_0 %296
%253 = OpLoad %v4float %252
%255 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_1 %294
%255 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_1 %296
%256 = OpLoad %v4float %255
%257 = OpFNegate %v4float %256
%258 = OpFAdd %v4float %253 %257
%260 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_2 %294
%260 = OpAccessChain %_ptr_Input_v4float %in_interpolators %int_2 %296
%261 = OpLoad %v4float %260
%262 = OpFAdd %v4float %258 %261
%263 = OpAccessChain %_ptr_Output_v4float %out_interpolators %294
%263 = OpAccessChain %_ptr_Output_v4float %out_interpolators %296
OpStore %263 %262
%265 = OpIAdd %int %294 %int_1
%265 = OpIAdd %int %296 %int_1
OpBranch %243
%245 = OpLabel
OpEmitVertex

View File

@@ -23,8 +23,8 @@
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/vulkan/texture_config.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_instance.h"
#include "xenia/ui/vulkan/vulkan_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_util.h"
DECLARE_bool(texture_dump);
@@ -35,7 +35,7 @@ void TextureDump(const TextureInfo& src, void* buffer, size_t length);
namespace vulkan {
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
using namespace xe::literals;
@@ -58,20 +58,21 @@ const char* get_dimension_name(xenos::DataDimension dimension) {
TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
TraceWriter* trace_writer,
ui::vulkan::VulkanDevice* device)
ui::vulkan::VulkanProvider& provider)
: memory_(memory),
register_file_(register_file),
trace_writer_(trace_writer),
device_(device),
staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
provider_(provider),
staging_buffer_(provider, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
kStagingBufferSize),
wb_staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
wb_staging_buffer_(provider, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
kStagingBufferSize) {}
TextureCache::~TextureCache() { Shutdown(); }
VkResult TextureCache::Initialize() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
VkResult status = VK_SUCCESS;
// Descriptor pool used for all of our cached descriptors.
@@ -79,16 +80,16 @@ VkResult TextureCache::Initialize() {
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_sizes[0].descriptorCount = 32768;
descriptor_pool_ = std::make_unique<ui::vulkan::DescriptorPool>(
*device_, 32768,
provider_, 32768,
std::vector<VkDescriptorPoolSize>(pool_sizes, std::end(pool_sizes)));
wb_command_pool_ = std::make_unique<ui::vulkan::CommandBufferPool>(
*device_, device_->queue_family_index());
provider_, provider_.queue_family_graphics_compute());
// Check some device limits
// On low sampler counts: Rarely would we experience over 16 unique samplers.
// This code could be refactored to scale up/down to the # of samplers.
auto& limits = device_->device_info().properties.limits;
auto& limits = provider_.device_properties().limits;
if (limits.maxPerStageDescriptorSamplers < kMaxTextureSamplers ||
limits.maxPerStageDescriptorSampledImages < kMaxTextureSamplers) {
XELOGE(
@@ -120,7 +121,7 @@ VkResult TextureCache::Initialize() {
static_cast<uint32_t>(xe::countof(bindings));
descriptor_set_layout_info.pBindings = bindings;
status =
dfn.vkCreateDescriptorSetLayout(*device_, &descriptor_set_layout_info,
dfn.vkCreateDescriptorSetLayout(device, &descriptor_set_layout_info,
nullptr, &texture_descriptor_set_layout_);
if (status != VK_SUCCESS) {
return status;
@@ -138,14 +139,16 @@ VkResult TextureCache::Initialize() {
// Create a memory allocator for textures.
VmaVulkanFunctions vulkan_funcs = {};
ui::vulkan::FillVMAVulkanFunctions(&vulkan_funcs, *device_);
ui::vulkan::FillVMAVulkanFunctions(&vulkan_funcs, provider_);
VmaAllocatorCreateInfo alloc_info = {
0, *device_, *device_, 0, 0, nullptr, nullptr, 0, nullptr, &vulkan_funcs,
};
VmaAllocatorCreateInfo alloc_info = {};
alloc_info.physicalDevice = provider_.physical_device();
alloc_info.device = device;
alloc_info.pVulkanFunctions = &vulkan_funcs;
alloc_info.instance = provider_.instance();
status = vmaCreateAllocator(&alloc_info, &mem_allocator_);
if (status != VK_SUCCESS) {
dfn.vkDestroyDescriptorSetLayout(*device_, texture_descriptor_set_layout_,
dfn.vkDestroyDescriptorSetLayout(device, texture_descriptor_set_layout_,
nullptr);
return status;
}
@@ -154,8 +157,6 @@ VkResult TextureCache::Initialize() {
invalidated_textures_sets_[1].reserve(64);
invalidated_textures_ = &invalidated_textures_sets_[0];
device_queue_ = device_->AcquireQueue(device_->queue_family_index());
memory_invalidation_callback_handle_ =
memory_->RegisterPhysicalMemoryInvalidationCallback(
MemoryInvalidationCallbackThunk, this);
@@ -170,10 +171,6 @@ void TextureCache::Shutdown() {
memory_invalidation_callback_handle_ = nullptr;
}
if (device_queue_) {
device_->ReleaseQueue(device_queue_, device_->queue_family_index());
}
// Free all textures allocated.
ClearCache();
Scavenge();
@@ -182,8 +179,9 @@ void TextureCache::Shutdown() {
vmaDestroyAllocator(mem_allocator_);
mem_allocator_ = nullptr;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkDestroyDescriptorSetLayout(*device_, texture_descriptor_set_layout_,
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
dfn.vkDestroyDescriptorSetLayout(device, texture_descriptor_set_layout_,
nullptr);
}
@@ -235,20 +233,19 @@ TextureCache::Texture* TextureCache::AllocateTexture(
image_info.usage =
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
const ui::vulkan::VulkanInstance* instance = device_->instance();
const ui::vulkan::VulkanInstance::InstanceFunctions& ifn = instance->ifn();
const ui::vulkan::VulkanProvider::InstanceFunctions& ifn = provider_.ifn();
// Check the device limits for the format before we create it.
VkFormatProperties props;
ifn.vkGetPhysicalDeviceFormatProperties(*device_, format, &props);
ifn.vkGetPhysicalDeviceFormatProperties(provider_.physical_device(), 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 {} ({})\n\t"
"(requested: {})",
texture_info.format_info()->name, ui::vulkan::to_string(format),
ui::vulkan::to_flags_string(static_cast<VkFormatFeatureFlagBits>(
required_flags & ~props.optimalTilingFeatures)));
"Texture Cache: Invalid usage flag specified on format {} (0x{:X})\n\t"
"(requested: 0x{:X})",
texture_info.format_info()->name, uint32_t(format),
uint32_t(required_flags & ~props.optimalTilingFeatures));
}
if (texture_info.dimension != xenos::DataDimension::kCube &&
@@ -267,8 +264,8 @@ TextureCache::Texture* TextureCache::AllocateTexture(
VkImageFormatProperties image_props;
ifn.vkGetPhysicalDeviceImageFormatProperties(
*device_, format, image_info.imageType, image_info.tiling,
image_info.usage, image_info.flags, &image_props);
provider_.physical_device(), format, image_info.imageType,
image_info.tiling, image_info.usage, image_info.flags, &image_props);
// TODO(DrChat): Actually check the image properties.
@@ -317,10 +314,11 @@ TextureCache::Texture* TextureCache::AllocateTexture(
}
bool TextureCache::FreeTexture(Texture* texture) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
if (texture->in_flight_fence) {
VkResult status = dfn.vkGetFenceStatus(*device_, texture->in_flight_fence);
VkResult status = dfn.vkGetFenceStatus(device, texture->in_flight_fence);
if (status != VK_SUCCESS && status != VK_ERROR_DEVICE_LOST) {
// Texture still in flight.
return false;
@@ -328,11 +326,11 @@ bool TextureCache::FreeTexture(Texture* texture) {
}
if (texture->framebuffer) {
dfn.vkDestroyFramebuffer(*device_, texture->framebuffer, nullptr);
dfn.vkDestroyFramebuffer(device, texture->framebuffer, nullptr);
}
for (auto it = texture->views.begin(); it != texture->views.end();) {
dfn.vkDestroyImageView(*device_, (*it)->view, nullptr);
dfn.vkDestroyImageView(device, (*it)->view, nullptr);
it = texture->views.erase(it);
}
@@ -529,14 +527,14 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
}
// Setup a debug name for the texture.
device_->DbgSetObjectName(
reinterpret_cast<uint64_t>(texture->image),
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
provider_.SetDeviceObjectName(
VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image),
fmt::format(
"RT: 0x{:08X} - 0x{:08X} ({}, {})", texture_info.memory.base_address,
texture_info.memory.base_address + texture_info.memory.base_size,
texture_info.format_info()->name,
get_dimension_name(texture_info.dimension)));
get_dimension_name(texture_info.dimension))
.c_str());
// Setup an access watch. If this texture is touched, it is destroyed.
WatchTexture(texture);
@@ -612,14 +610,14 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
}
// Setup a debug name for the texture.
device_->DbgSetObjectName(
reinterpret_cast<uint64_t>(texture->image),
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
provider_.SetDeviceObjectName(
VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image),
fmt::format(
"T: 0x{:08X} - 0x{:08X} ({}, {})", texture_info.memory.base_address,
texture_info.memory.base_address + texture_info.memory.base_size,
texture_info.format_info()->name,
get_dimension_name(texture_info.dimension)));
get_dimension_name(texture_info.dimension))
.c_str());
textures_[texture_hash] = texture;
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
@@ -703,8 +701,9 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
!is_cube ? 1 : 1 + texture->texture_info.depth;
VkImageView view;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
auto status = dfn.vkCreateImageView(*device_, &view_info, nullptr, &view);
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
auto status = dfn.vkCreateImageView(device, &view_info, nullptr, &view);
CheckResult(status, "vkCreateImageView");
if (status == VK_SUCCESS) {
auto texture_view = new TextureView();
@@ -844,9 +843,10 @@ TextureCache::Sampler* TextureCache::Demand(const SamplerInfo& sampler_info) {
sampler_create_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
sampler_create_info.unnormalizedCoordinates = VK_FALSE;
VkSampler vk_sampler;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
status =
dfn.vkCreateSampler(*device_, &sampler_create_info, nullptr, &vk_sampler);
dfn.vkCreateSampler(device, &sampler_create_info, nullptr, &vk_sampler);
CheckResult(status, "vkCreateSampler");
if (status != VK_SUCCESS) {
return nullptr;
@@ -960,7 +960,8 @@ TextureCache::Texture* TextureCache::LookupAddress(uint32_t guest_address,
void TextureCache::FlushPendingCommands(VkCommandBuffer command_buffer,
VkFence completion_fence) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
auto status = dfn.vkEndCommandBuffer(command_buffer);
CheckResult(status, "vkEndCommandBuffer");
@@ -970,21 +971,17 @@ void TextureCache::FlushPendingCommands(VkCommandBuffer command_buffer,
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer;
if (device_queue_) {
auto status =
dfn.vkQueueSubmit(device_queue_, 1, &submit_info, completion_fence);
CheckResult(status, "vkQueueSubmit");
} else {
std::lock_guard<std::mutex> lock(device_->primary_queue_mutex());
auto status = dfn.vkQueueSubmit(device_->primary_queue(), 1, &submit_info,
{
ui::vulkan::VulkanProvider::QueueAcquisition queue_acquisition(
provider_.AcquireQueue(provider_.queue_family_graphics_compute(), 0));
auto status = dfn.vkQueueSubmit(queue_acquisition.queue, 1, &submit_info,
completion_fence);
CheckResult(status, "vkQueueSubmit");
}
dfn.vkWaitForFences(*device_, 1, &completion_fence, VK_TRUE, -1);
dfn.vkWaitForFences(device, 1, &completion_fence, VK_TRUE, -1);
staging_buffer_.Scavenge();
dfn.vkResetFences(*device_, 1, &completion_fence);
dfn.vkResetFences(device, 1, &completion_fence);
// Reset the command buffer and put it back into the recording state.
dfn.vkResetCommandBuffer(command_buffer, 0);
@@ -1169,7 +1166,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
TextureDump(src, unpack_buffer, unpack_length);
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
// Transition the texture into a transfer destination layout.
VkImageMemoryBarrier barrier;
@@ -1313,7 +1310,7 @@ uint32_t TextureCache::ComputeTextureStorage(const TextureInfo& src) {
}
void TextureCache::WritebackTexture(Texture* texture) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkResult status = VK_SUCCESS;
VkFence fence = wb_command_pool_->BeginBatch();
auto alloc = wb_staging_buffer_.Acquire(texture->alloc_info.size, fence);
@@ -1361,7 +1358,8 @@ void TextureCache::WritebackTexture(Texture* texture) {
// Submit the command buffer.
// Submit commands and wait.
{
std::lock_guard<std::mutex> lock(device_->primary_queue_mutex());
ui::vulkan::VulkanProvider::QueueAcquisition queue_acquisition(
provider_.AcquireQueue(provider_.queue_family_graphics_compute(), 0));
VkSubmitInfo submit_info = {
VK_STRUCTURE_TYPE_SUBMIT_INFO,
nullptr,
@@ -1373,12 +1371,11 @@ void TextureCache::WritebackTexture(Texture* texture) {
0,
nullptr,
};
status =
dfn.vkQueueSubmit(device_->primary_queue(), 1, &submit_info, fence);
status = dfn.vkQueueSubmit(queue_acquisition.queue, 1, &submit_info, fence);
CheckResult(status, "vkQueueSubmit");
if (status == VK_SUCCESS) {
status = dfn.vkQueueWaitIdle(device_->primary_queue());
status = dfn.vkQueueWaitIdle(queue_acquisition.queue);
CheckResult(status, "vkQueueWaitIdle");
}
}
@@ -1471,8 +1468,9 @@ VkDescriptorSet TextureCache::PrepareTextureSet(
// Update the descriptor set.
if (update_set_info->image_write_count > 0) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkUpdateDescriptorSets(*device_, update_set_info->image_write_count,
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
dfn.vkUpdateDescriptorSets(device, update_set_info->image_write_count,
update_set_info->image_writes, 0, nullptr);
}
@@ -1632,9 +1630,10 @@ void TextureCache::ClearCache() {
textures_.clear();
COUNT_profile_set("gpu/texture_cache/textures", 0);
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider_.dfn();
VkDevice device = provider_.device();
for (auto it = samplers_.begin(); it != samplers_.end(); ++it) {
dfn.vkDestroySampler(*device_, it->second->sampler, nullptr);
dfn.vkDestroySampler(device, it->second->sampler, nullptr);
delete it->second;
}
samplers_.clear();

View File

@@ -26,10 +26,8 @@
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/circular_buffer.h"
#include "xenia/ui/vulkan/fenced_pools.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "third_party/vulkan/vk_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_mem_alloc.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {
@@ -78,7 +76,7 @@ class TextureCache {
};
TextureCache(Memory* memory, RegisterFile* register_file,
TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device);
TraceWriter* trace_writer, ui::vulkan::VulkanProvider& provider);
~TextureCache();
VkResult Initialize();
@@ -203,8 +201,7 @@ class TextureCache {
RegisterFile* register_file_ = nullptr;
TraceWriter* trace_writer_ = nullptr;
ui::vulkan::VulkanDevice* device_ = nullptr;
VkQueue device_queue_ = nullptr;
ui::vulkan::VulkanProvider& provider_;
std::unique_ptr<xe::ui::vulkan::CommandBufferPool> wb_command_pool_ = nullptr;
std::unique_ptr<xe::ui::vulkan::DescriptorPool> descriptor_pool_ = nullptr;

View File

@@ -12,7 +12,7 @@
#include "xenia/gpu/texture_info.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {

View File

@@ -21,6 +21,7 @@
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/vulkan_presenter.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
@@ -29,21 +30,22 @@ namespace vulkan {
using namespace xe::literals;
using namespace xe::gpu::xenos;
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
constexpr size_t kDefaultBufferCacheCapacity = 256_MiB;
VulkanCommandProcessor::VulkanCommandProcessor(
VulkanGraphicsSystem* graphics_system, kernel::KernelState* kernel_state)
: CommandProcessor(graphics_system, kernel_state) {}
: CommandProcessor(graphics_system, kernel_state),
swap_submission_tracker_(GetVulkanProvider()) {}
VulkanCommandProcessor::~VulkanCommandProcessor() = default;
void VulkanCommandProcessor::RequestFrameTrace(
const std::filesystem::path& root_path) {
// Override traces if renderdoc is attached.
if (device_->is_renderdoc_attached()) {
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
if (provider.renderdoc_api().api_1_0_0()) {
trace_requested_ = true;
return;
}
@@ -67,21 +69,12 @@ bool VulkanCommandProcessor::SetupContext() {
return false;
}
// Acquire our device and queue.
auto context = static_cast<xe::ui::vulkan::VulkanContext*>(context_.get());
device_ = context->device();
queue_ = device_->AcquireQueue(device_->queue_family_index());
if (!queue_) {
// Need to reuse primary queue (with locks).
queue_ = device_->primary_queue();
queue_mutex_ = &device_->primary_queue_mutex();
}
ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
VkResult status = VK_SUCCESS;
// Setup a blitter.
blitter_ = std::make_unique<ui::vulkan::Blitter>();
status = blitter_->Initialize(device_);
blitter_ = std::make_unique<ui::vulkan::Blitter>(provider);
status = blitter_->Initialize();
if (status != VK_SUCCESS) {
XELOGE("Unable to initialize blitter");
blitter_->Shutdown();
@@ -90,11 +83,11 @@ bool VulkanCommandProcessor::SetupContext() {
// Setup fenced pools used for all our per-frame/per-draw resources.
command_buffer_pool_ = std::make_unique<ui::vulkan::CommandBufferPool>(
*device_, device_->queue_family_index());
provider, provider.queue_family_graphics_compute());
// Initialize the state machine caches.
buffer_cache_ = std::make_unique<BufferCache>(
register_file_, memory_, device_, kDefaultBufferCacheCapacity);
register_file_, memory_, provider, kDefaultBufferCacheCapacity);
status = buffer_cache_->Initialize();
if (status != VK_SUCCESS) {
XELOGE("Unable to initialize buffer cache");
@@ -103,7 +96,7 @@ bool VulkanCommandProcessor::SetupContext() {
}
texture_cache_ = std::make_unique<TextureCache>(memory_, register_file_,
&trace_writer_, device_);
&trace_writer_, provider);
status = texture_cache_->Initialize();
if (status != VK_SUCCESS) {
XELOGE("Unable to initialize texture cache");
@@ -111,7 +104,7 @@ bool VulkanCommandProcessor::SetupContext() {
return false;
}
pipeline_cache_ = std::make_unique<PipelineCache>(register_file_, device_);
pipeline_cache_ = std::make_unique<PipelineCache>(register_file_, provider);
status = pipeline_cache_->Initialize(
buffer_cache_->constant_descriptor_set_layout(),
texture_cache_->texture_descriptor_set_layout(),
@@ -122,7 +115,7 @@ bool VulkanCommandProcessor::SetupContext() {
return false;
}
render_cache_ = std::make_unique<RenderCache>(register_file_, device_);
render_cache_ = std::make_unique<RenderCache>(register_file_, provider);
status = render_cache_->Initialize();
if (status != VK_SUCCESS) {
XELOGE("Unable to initialize render cache");
@@ -136,10 +129,14 @@ bool VulkanCommandProcessor::SetupContext() {
void VulkanCommandProcessor::ShutdownContext() {
// TODO(benvanik): wait until idle.
if (swap_state_.front_buffer_texture) {
// Free swap chain image.
DestroySwapImage();
}
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
swap_submission_tracker_.Shutdown();
ui::vulkan::util::DestroyAndNullHandle(dfn.vkDestroyFramebuffer, device,
swap_framebuffer_);
swap_framebuffer_version_ = UINT64_MAX;
buffer_cache_.reset();
pipeline_cache_.reset();
@@ -151,12 +148,6 @@ void VulkanCommandProcessor::ShutdownContext() {
// Free all pools. This must come after all of our caches clean up.
command_buffer_pool_.reset();
// Release queue, if we were using an acquired one.
if (!queue_mutex_) {
device_->ReleaseQueue(queue_, device_->queue_family_index());
queue_ = nullptr;
}
CommandProcessor::ShutdownContext();
}
@@ -178,26 +169,6 @@ void VulkanCommandProcessor::MakeCoherent() {
}
}
void VulkanCommandProcessor::PrepareForWait() {
SCOPE_profile_cpu_f("gpu");
CommandProcessor::PrepareForWait();
// TODO(benvanik): fences and fancy stuff. We should figure out a way to
// make interrupt callbacks from the GPU so that we don't have to do a full
// synchronize here.
// glFlush();
// glFinish();
context_->ClearCurrent();
}
void VulkanCommandProcessor::ReturnFromWait() {
context_->MakeCurrent();
CommandProcessor::ReturnFromWait();
}
void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
CommandProcessor::WriteRegister(index, value);
@@ -223,7 +194,7 @@ void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
} else if (index == XE_GPU_REG_DC_LUT_PWL_DATA) {
UpdateGammaRampValue(GammaRampType::kPWL, value);
} else if (index == XE_GPU_REG_DC_LUT_30_COLOR) {
UpdateGammaRampValue(GammaRampType::kNormal, value);
UpdateGammaRampValue(GammaRampType::kTable, value);
} else if (index >= XE_GPU_REG_DC_LUT_RW_MODE &&
index <= XE_GPU_REG_DC_LUTA_CONTROL) {
uint32_t offset = index - XE_GPU_REG_DC_LUT_RW_MODE;
@@ -237,109 +208,6 @@ void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
}
}
void VulkanCommandProcessor::CreateSwapImage(VkCommandBuffer setup_buffer,
VkExtent2D extents) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
VkImageCreateInfo image_info;
std::memset(&image_info, 0, sizeof(VkImageCreateInfo));
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = VK_FORMAT_R8G8B8A8_UNORM;
image_info.extent = {extents.width, extents.height, 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_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_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_fb;
auto status = dfn.vkCreateImage(*device_, &image_info, nullptr, &image_fb);
CheckResult(status, "vkCreateImage");
// Bind memory to image.
VkMemoryRequirements mem_requirements;
dfn.vkGetImageMemoryRequirements(*device_, image_fb, &mem_requirements);
fb_memory_ = device_->AllocateMemory(mem_requirements, 0);
assert_not_null(fb_memory_);
status = dfn.vkBindImageMemory(*device_, image_fb, fb_memory_, 0);
CheckResult(status, "vkBindImageMemory");
std::lock_guard<std::mutex> lock(swap_state_.mutex);
swap_state_.front_buffer_texture = reinterpret_cast<uintptr_t>(image_fb);
VkImageViewCreateInfo view_create_info = {
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
nullptr,
0,
image_fb,
VK_IMAGE_VIEW_TYPE_2D,
VK_FORMAT_R8G8B8A8_UNORM,
{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A},
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
};
status = dfn.vkCreateImageView(*device_, &view_create_info, nullptr,
&fb_image_view_);
CheckResult(status, "vkCreateImageView");
VkFramebufferCreateInfo framebuffer_create_info = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr,
0,
blitter_->GetRenderPass(VK_FORMAT_R8G8B8A8_UNORM, true),
1,
&fb_image_view_,
extents.width,
extents.height,
1,
};
status = dfn.vkCreateFramebuffer(*device_, &framebuffer_create_info, nullptr,
&fb_framebuffer_);
CheckResult(status, "vkCreateFramebuffer");
// Transition image to general layout.
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image_fb;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
dfn.vkCmdPipelineBarrier(setup_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0,
nullptr, 0, nullptr, 1, &barrier);
}
void VulkanCommandProcessor::DestroySwapImage() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkDestroyFramebuffer(*device_, fb_framebuffer_, nullptr);
dfn.vkDestroyImageView(*device_, fb_image_view_, nullptr);
std::lock_guard<std::mutex> lock(swap_state_.mutex);
dfn.vkDestroyImage(
*device_, reinterpret_cast<VkImage>(swap_state_.front_buffer_texture),
nullptr);
dfn.vkFreeMemory(*device_, fb_memory_, nullptr);
swap_state_.front_buffer_texture = 0;
fb_memory_ = nullptr;
fb_framebuffer_ = nullptr;
fb_image_view_ = nullptr;
}
void VulkanCommandProcessor::BeginFrame() {
assert_false(frame_open_);
@@ -351,7 +219,8 @@ void VulkanCommandProcessor::BeginFrame() {
current_command_buffer_ = command_buffer_pool_->AcquireEntry();
current_setup_buffer_ = command_buffer_pool_->AcquireEntry();
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkCommandBufferBeginInfo command_buffer_begin_info;
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -368,19 +237,14 @@ void VulkanCommandProcessor::BeginFrame() {
// Flag renderdoc down to start a capture if requested.
// The capture will end when these commands are submitted to the queue.
static uint32_t frame = 0;
if (device_->is_renderdoc_attached() && !capturing_ &&
(cvars::vulkan_renderdoc_capture_all || trace_requested_)) {
if (queue_mutex_) {
queue_mutex_->lock();
}
capturing_ = true;
trace_requested_ = false;
device_->BeginRenderDocFrameCapture();
if (queue_mutex_) {
queue_mutex_->unlock();
if ((cvars::vulkan_renderdoc_capture_all || trace_requested_) &&
!capturing_) {
const RENDERDOC_API_1_0_0* renderdoc_api =
provider.renderdoc_api().api_1_0_0();
if (renderdoc_api && !renderdoc_api->IsFrameCapturing()) {
capturing_ = true;
trace_requested_ = false;
renderdoc_api->StartFrameCapture(nullptr, nullptr);
}
}
@@ -393,7 +257,8 @@ void VulkanCommandProcessor::EndFrame() {
current_render_state_ = nullptr;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkResult status = VK_SUCCESS;
status = dfn.vkEndCommandBuffer(current_setup_buffer_);
CheckResult(status, "vkEndCommandBuffer");
@@ -407,170 +272,348 @@ void VulkanCommandProcessor::EndFrame() {
frame_open_ = false;
}
void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
uint32_t frontbuffer_width,
uint32_t frontbuffer_height) {
void VulkanCommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
uint32_t frontbuffer_width,
uint32_t frontbuffer_height) {
SCOPE_profile_cpu_f("gpu");
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
// Build a final command buffer that copies the game's frontbuffer texture
// into our backbuffer texture.
VkCommandBuffer copy_commands = nullptr;
bool opened_batch;
if (command_buffer_pool_->has_open_batch()) {
copy_commands = command_buffer_pool_->AcquireEntry();
opened_batch = false;
} else {
current_batch_fence_ = command_buffer_pool_->BeginBatch();
copy_commands = command_buffer_pool_->AcquireEntry();
opened_batch = true;
ui::Presenter* presenter = graphics_system_->presenter();
if (!presenter) {
return;
}
VkCommandBufferBeginInfo begin_info;
std::memset(&begin_info, 0, sizeof(begin_info));
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
auto status = dfn.vkBeginCommandBuffer(copy_commands, &begin_info);
CheckResult(status, "vkBeginCommandBuffer");
if (!frontbuffer_ptr) {
// Trace viewer does this.
frontbuffer_ptr = last_copy_base_;
}
if (!swap_state_.front_buffer_texture) {
CreateSwapImage(copy_commands, {frontbuffer_width, frontbuffer_height});
}
auto swap_fb = reinterpret_cast<VkImage>(swap_state_.front_buffer_texture);
auto& regs = *register_file_;
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0;
auto group =
reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(&regs.values[r]);
auto& fetch = group->texture_fetch;
TextureInfo texture_info;
if (!TextureInfo::Prepare(group->texture_fetch, &texture_info)) {
assert_always();
}
// Issue the commands to copy the game's frontbuffer to our backbuffer.
auto texture = texture_cache_->Lookup(texture_info);
if (texture) {
texture->in_flight_fence = current_batch_fence_;
// Insert a barrier so the GPU finishes writing to the image.
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
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.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = texture->image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
dfn.vkCmdPipelineBarrier(copy_commands,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0,
nullptr, 0, nullptr, 1, &barrier);
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.image = swap_fb;
dfn.vkCmdPipelineBarrier(copy_commands, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
0, nullptr, 0, nullptr, 1, &barrier);
// Part of the source image that we want to blit from.
VkRect2D src_rect = {
{0, 0},
{texture->texture_info.width + 1, texture->texture_info.height + 1},
};
VkRect2D dst_rect = {{0, 0}, {frontbuffer_width, frontbuffer_height}};
VkViewport viewport = {
0.f, 0.f, float(frontbuffer_width), float(frontbuffer_height),
0.f, 1.f};
VkRect2D scissor = {{0, 0}, {frontbuffer_width, frontbuffer_height}};
blitter_->BlitTexture2D(
copy_commands, current_batch_fence_,
texture_cache_->DemandView(texture, 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,
scissor, VK_FILTER_LINEAR, true, true);
std::swap(barrier.oldLayout, barrier.newLayout);
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dfn.vkCmdPipelineBarrier(
copy_commands, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
std::lock_guard<std::mutex> lock(swap_state_.mutex);
swap_state_.width = frontbuffer_width;
swap_state_.height = frontbuffer_height;
}
status = dfn.vkEndCommandBuffer(copy_commands);
CheckResult(status, "vkEndCommandBuffer");
// Queue up current command buffers.
// TODO(benvanik): bigger batches.
std::vector<VkCommandBuffer> submit_buffers;
if (frame_open_) {
// TODO(DrChat): If the setup buffer is empty, don't bother queueing it up.
submit_buffers.push_back(current_setup_buffer_);
submit_buffers.push_back(current_command_buffer_);
EndFrame();
}
bool submitted = false;
auto& regs = *register_file_;
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0;
auto group =
reinterpret_cast<const xenos::xe_gpu_fetch_group_t*>(&regs.values[r]);
TextureInfo texture_info;
if (!TextureInfo::Prepare(group->texture_fetch, &texture_info)) {
assert_always();
}
auto texture = texture_cache_->Lookup(texture_info);
if (texture) {
presenter->RefreshGuestOutput(
frontbuffer_width, frontbuffer_height, 1280, 720,
[this, frontbuffer_width, frontbuffer_height, texture, &submit_buffers,
&submitted](
ui::Presenter::GuestOutputRefreshContext& context) -> bool {
auto& vulkan_context = static_cast<
ui::vulkan::VulkanPresenter::VulkanGuestOutputRefreshContext&>(
context);
ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn =
provider.dfn();
VkDevice device = provider.device();
// Make sure the framebuffer is for the current guest output image.
if (swap_framebuffer_ != VK_NULL_HANDLE &&
swap_framebuffer_version_ != vulkan_context.image_version()) {
swap_submission_tracker_.AwaitAllSubmissionsCompletion();
dfn.vkDestroyFramebuffer(device, swap_framebuffer_, nullptr);
swap_framebuffer_ = VK_NULL_HANDLE;
}
if (swap_framebuffer_ == VK_NULL_HANDLE) {
VkRenderPass render_pass = blitter_->GetRenderPass(
ui::vulkan::VulkanPresenter::kGuestOutputFormat, true);
if (render_pass == VK_NULL_HANDLE) {
return false;
}
VkImageView guest_output_image_view = vulkan_context.image_view();
VkFramebufferCreateInfo swap_framebuffer_create_info;
swap_framebuffer_create_info.sType =
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
swap_framebuffer_create_info.pNext = nullptr;
swap_framebuffer_create_info.flags = 0;
swap_framebuffer_create_info.renderPass = render_pass;
swap_framebuffer_create_info.attachmentCount = 1;
swap_framebuffer_create_info.pAttachments =
&guest_output_image_view;
swap_framebuffer_create_info.width = frontbuffer_width;
swap_framebuffer_create_info.height = frontbuffer_height;
swap_framebuffer_create_info.layers = 1;
if (dfn.vkCreateFramebuffer(device, &swap_framebuffer_create_info,
nullptr,
&swap_framebuffer_) != VK_SUCCESS) {
XELOGE(
"Failed to create the Vulkan framebuffer for presentation");
return false;
}
swap_framebuffer_version_ = vulkan_context.image_version();
}
// Build a final command buffer that copies the game's frontbuffer
// texture into our backbuffer texture.
VkCommandBuffer copy_commands = nullptr;
bool opened_batch = !command_buffer_pool_->has_open_batch();
if (!command_buffer_pool_->has_open_batch()) {
current_batch_fence_ = command_buffer_pool_->BeginBatch();
}
copy_commands = command_buffer_pool_->AcquireEntry();
VkCommandBufferBeginInfo command_buffer_begin_info;
command_buffer_begin_info.sType =
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.pNext = nullptr;
command_buffer_begin_info.flags =
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
command_buffer_begin_info.pInheritanceInfo = nullptr;
dfn.vkBeginCommandBuffer(copy_commands, &command_buffer_begin_info);
texture->in_flight_fence = current_batch_fence_;
// Insert a barrier so the GPU finishes writing to the image, and a
// barrier after the last presenter's usage of the guest output image.
VkPipelineStageFlags acquire_barrier_src_stages = 0;
VkPipelineStageFlags acquire_barrier_dst_stages = 0;
VkImageMemoryBarrier acquire_image_memory_barriers[2];
uint32_t acquire_image_memory_barrier_count = 0;
{
acquire_barrier_src_stages |=
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
acquire_barrier_dst_stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
VkImageMemoryBarrier& acquire_image_memory_barrier =
acquire_image_memory_barriers
[acquire_image_memory_barrier_count++];
acquire_image_memory_barrier.sType =
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
acquire_image_memory_barrier.pNext = nullptr;
acquire_image_memory_barrier.srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFER_WRITE_BIT;
acquire_image_memory_barrier.dstAccessMask =
VK_ACCESS_SHADER_READ_BIT;
acquire_image_memory_barrier.oldLayout = texture->image_layout;
acquire_image_memory_barrier.newLayout = texture->image_layout;
acquire_image_memory_barrier.srcQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
acquire_image_memory_barrier.dstQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
acquire_image_memory_barrier.image = texture->image;
ui::vulkan::util::InitializeSubresourceRange(
acquire_image_memory_barrier.subresourceRange);
}
{
acquire_barrier_dst_stages |=
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkImageMemoryBarrier& acquire_image_memory_barrier =
acquire_image_memory_barriers
[acquire_image_memory_barrier_count++];
acquire_image_memory_barrier.sType =
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
acquire_image_memory_barrier.pNext = nullptr;
acquire_image_memory_barrier.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
// Will be overwriting all the contents.
acquire_image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
acquire_image_memory_barrier.newLayout =
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
acquire_image_memory_barrier.srcQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
acquire_image_memory_barrier.dstQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
acquire_image_memory_barrier.image = vulkan_context.image();
ui::vulkan::util::InitializeSubresourceRange(
acquire_image_memory_barrier.subresourceRange);
if (vulkan_context.image_ever_written_previously()) {
acquire_barrier_src_stages |=
ui::vulkan::VulkanPresenter::kGuestOutputInternalStageMask;
acquire_image_memory_barrier.srcAccessMask =
ui::vulkan::VulkanPresenter::kGuestOutputInternalAccessMask;
} else {
acquire_image_memory_barrier.srcAccessMask = 0;
}
}
assert_not_zero(acquire_barrier_src_stages);
assert_not_zero(acquire_barrier_dst_stages);
assert_not_zero(acquire_image_memory_barrier_count);
dfn.vkCmdPipelineBarrier(copy_commands, acquire_barrier_src_stages,
acquire_barrier_dst_stages, 0, 0, nullptr, 0,
nullptr, acquire_image_memory_barrier_count,
acquire_image_memory_barriers);
// Part of the source image that we want to blit from.
VkRect2D src_rect = {
{0, 0},
{texture->texture_info.width + 1,
texture->texture_info.height + 1},
};
VkRect2D dst_rect = {{0, 0}, {frontbuffer_width, frontbuffer_height}};
VkViewport viewport = {
0.f, 0.f, float(frontbuffer_width), float(frontbuffer_height),
0.f, 1.f};
VkRect2D scissor = {{0, 0}, {frontbuffer_width, frontbuffer_height}};
blitter_->BlitTexture2D(
copy_commands, current_batch_fence_,
texture_cache_->DemandView(texture, 0x688)->view, src_rect,
{texture->texture_info.width + 1,
texture->texture_info.height + 1},
ui::vulkan::VulkanPresenter::kGuestOutputFormat, dst_rect,
{frontbuffer_width, frontbuffer_height}, swap_framebuffer_,
viewport, scissor, VK_FILTER_LINEAR, true, true);
VkPipelineStageFlags release_barrier_src_stages = 0;
VkPipelineStageFlags release_barrier_dst_stages = 0;
VkImageMemoryBarrier release_image_memory_barriers[2];
uint32_t release_image_memory_barrier_count = 0;
{
release_barrier_src_stages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
release_barrier_dst_stages |=
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT;
VkImageMemoryBarrier& release_image_memory_barrier =
release_image_memory_barriers
[release_image_memory_barrier_count++];
release_image_memory_barrier.sType =
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
release_image_memory_barrier.pNext = nullptr;
release_image_memory_barrier.srcAccessMask =
VK_ACCESS_SHADER_READ_BIT;
release_image_memory_barrier.dstAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_TRANSFER_WRITE_BIT;
release_image_memory_barrier.oldLayout = texture->image_layout;
release_image_memory_barrier.newLayout = texture->image_layout;
release_image_memory_barrier.srcQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
release_image_memory_barrier.dstQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
release_image_memory_barrier.image = texture->image;
ui::vulkan::util::InitializeSubresourceRange(
release_image_memory_barrier.subresourceRange);
}
{
release_barrier_src_stages |=
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
release_barrier_dst_stages |=
ui::vulkan::VulkanPresenter::kGuestOutputInternalStageMask;
VkImageMemoryBarrier& release_image_memory_barrier =
release_image_memory_barriers
[release_image_memory_barrier_count++];
release_image_memory_barrier.sType =
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
release_image_memory_barrier.pNext = nullptr;
release_image_memory_barrier.srcAccessMask =
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
release_image_memory_barrier.dstAccessMask =
ui::vulkan::VulkanPresenter::kGuestOutputInternalAccessMask;
release_image_memory_barrier.oldLayout =
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
release_image_memory_barrier.newLayout =
ui::vulkan::VulkanPresenter::kGuestOutputInternalLayout;
release_image_memory_barrier.srcQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
release_image_memory_barrier.dstQueueFamilyIndex =
VK_QUEUE_FAMILY_IGNORED;
release_image_memory_barrier.image = vulkan_context.image();
ui::vulkan::util::InitializeSubresourceRange(
release_image_memory_barrier.subresourceRange);
}
assert_not_zero(release_barrier_src_stages);
assert_not_zero(release_barrier_dst_stages);
assert_not_zero(release_image_memory_barrier_count);
dfn.vkCmdPipelineBarrier(copy_commands, release_barrier_src_stages,
release_barrier_dst_stages, 0, 0, nullptr, 0,
nullptr, release_image_memory_barrier_count,
release_image_memory_barriers);
dfn.vkEndCommandBuffer(copy_commands);
// Need to submit all the commands before giving the image back to the
// presenter so it can submit its own commands for displaying it to
// the queue.
if (frame_open_) {
EndFrame();
}
if (opened_batch) {
command_buffer_pool_->EndBatch();
}
submit_buffers.push_back(copy_commands);
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = uint32_t(submit_buffers.size());
submit_info.pCommandBuffers = submit_buffers.data();
VkResult submit_result;
{
ui::vulkan::VulkanProvider::QueueAcquisition queue_acquisition(
provider.AcquireQueue(provider.queue_family_graphics_compute(),
0));
submit_result = dfn.vkQueueSubmit(
queue_acquisition.queue, 1, &submit_info, current_batch_fence_);
}
if (submit_result != VK_SUCCESS) {
return false;
}
submitted = true;
// Signal the fence for destroying objects depending on the guest
// output image.
{
ui::vulkan::VulkanSubmissionTracker::FenceAcquisition
fence_acqusition =
swap_submission_tracker_.AcquireFenceToAdvanceSubmission();
ui::vulkan::VulkanProvider::QueueAcquisition queue_acquisition(
provider.AcquireQueue(provider.queue_family_graphics_compute(),
0));
if (dfn.vkQueueSubmit(queue_acquisition.queue, 0, nullptr,
fence_acqusition.fence()) != VK_SUCCESS) {
fence_acqusition.SubmissionSucceededSignalFailed();
}
}
return true;
});
}
if (opened_batch) {
command_buffer_pool_->EndBatch();
}
ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
submit_buffers.push_back(copy_commands);
if (!submit_buffers.empty()) {
// TODO(benvanik): move to CP or to host (trace dump, etc).
// This only needs to surround a vkQueueSubmit.
if (queue_mutex_) {
queue_mutex_->lock();
if (!submitted) {
// End the frame even if failed to refresh the guest output.
if (frame_open_) {
EndFrame();
}
VkSubmitInfo submit_info;
std::memset(&submit_info, 0, sizeof(VkSubmitInfo));
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = uint32_t(submit_buffers.size());
submit_info.pCommandBuffers = submit_buffers.data();
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
status = dfn.vkQueueSubmit(queue_, 1, &submit_info, current_batch_fence_);
if (device_->is_renderdoc_attached() && capturing_) {
device_->EndRenderDocFrameCapture();
capturing_ = false;
}
if (queue_mutex_) {
queue_mutex_->unlock();
if (!submit_buffers.empty() || current_batch_fence_ != VK_NULL_HANDLE) {
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = uint32_t(submit_buffers.size());
submit_info.pCommandBuffers = submit_buffers.data();
VkResult submit_result;
{
ui::vulkan::VulkanProvider::QueueAcquisition queue_acquisition(
provider.AcquireQueue(provider.queue_family_graphics_compute(), 0));
submit_result = dfn.vkQueueSubmit(queue_acquisition.queue, 1,
&submit_info, current_batch_fence_);
}
CheckResult(submit_result, "vkQueueSubmit");
}
}
dfn.vkWaitForFences(*device_, 1, &current_batch_fence_, VK_TRUE, -1);
if (current_batch_fence_ != VK_NULL_HANDLE) {
dfn.vkWaitForFences(device, 1, &current_batch_fence_, VK_TRUE, -1);
}
if (cache_clear_requested_) {
cache_clear_requested_ = false;
@@ -675,7 +718,8 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
}
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
// Configure the pipeline for drawing.
// This encodes all render state (blend, depth, etc), our shader stages,
@@ -767,7 +811,8 @@ bool VulkanCommandProcessor::PopulateConstants(VkCommandBuffer command_buffer,
uint32_t set_constant_offsets[2] = {
static_cast<uint32_t>(constant_offsets.first),
static_cast<uint32_t>(constant_offsets.second)};
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
dfn.vkCmdBindDescriptorSets(
command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1,
&constant_descriptor_set,
@@ -820,7 +865,8 @@ bool VulkanCommandProcessor::PopulateIndexBuffer(
VkIndexType index_type = info.format == xenos::IndexFormat::kInt32
? VK_INDEX_TYPE_UINT32
: VK_INDEX_TYPE_UINT16;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
dfn.vkCmdBindIndexBuffer(command_buffer, buffer_ref.first, buffer_ref.second,
index_type);
@@ -850,7 +896,8 @@ bool VulkanCommandProcessor::PopulateVertexBuffers(
return false;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
dfn.vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_cache_->pipeline_layout(), 2, 1,
&descriptor_set, 0, nullptr);
@@ -875,7 +922,8 @@ bool VulkanCommandProcessor::PopulateSamplers(VkCommandBuffer command_buffer,
return false;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
dfn.vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_cache_->pipeline_layout(), 1, 1,
&descriptor_set, 0, nullptr);
@@ -1083,7 +1131,9 @@ bool VulkanCommandProcessor::IssueCopy() {
render_cache_->EndRenderPass();
current_render_state_ = nullptr;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
const ui::vulkan::VulkanProvider& provider = GetVulkanProvider();
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
auto command_buffer = current_command_buffer_;
if (texture->image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
@@ -1219,8 +1269,8 @@ bool VulkanCommandProcessor::IssueCopy() {
1,
};
VkResult res = dfn.vkCreateFramebuffer(*device_, &fb_create_info,
nullptr, &texture->framebuffer);
VkResult res = dfn.vkCreateFramebuffer(device, &fb_create_info, nullptr,
&texture->framebuffer);
CheckResult(res, "vkCreateFramebuffer");
}

View File

@@ -11,6 +11,7 @@
#define XENIA_GPU_VULKAN_VULKAN_COMMAND_PROCESSOR_H_
#include <atomic>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory>
@@ -27,21 +28,21 @@
#include "xenia/gpu/vulkan/pipeline_cache.h"
#include "xenia/gpu/vulkan/render_cache.h"
#include "xenia/gpu/vulkan/texture_cache.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/xthread.h"
#include "xenia/memory.h"
#include "xenia/ui/vulkan/blitter.h"
#include "xenia/ui/vulkan/fenced_pools.h"
#include "xenia/ui/vulkan/vulkan_context.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include "xenia/ui/vulkan/vulkan_submission_tracker.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
namespace gpu {
namespace vulkan {
class VulkanGraphicsSystem;
class TextureCache;
class VulkanCommandProcessor : public CommandProcessor {
@@ -55,6 +56,11 @@ class VulkanCommandProcessor : public CommandProcessor {
void RestoreEdramSnapshot(const void* snapshot) override;
void ClearCaches() override;
ui::vulkan::VulkanProvider& GetVulkanProvider() const {
return *static_cast<ui::vulkan::VulkanProvider*>(
graphics_system_->provider());
}
RenderCache* render_cache() { return render_cache_.get(); }
private:
@@ -62,19 +68,14 @@ class VulkanCommandProcessor : public CommandProcessor {
void ShutdownContext() override;
void MakeCoherent() override;
void PrepareForWait() override;
void ReturnFromWait() override;
void WriteRegister(uint32_t index, uint32_t value) override;
void BeginFrame();
void EndFrame();
void CreateSwapImage(VkCommandBuffer setup_buffer, VkExtent2D extents);
void DestroySwapImage();
void PerformSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) override;
void IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
uint32_t frontbuffer_height) override;
Shader* LoadShader(xenos::ShaderType shader_type, uint32_t guest_address,
const uint32_t* host_address,
@@ -99,13 +100,6 @@ class VulkanCommandProcessor : public CommandProcessor {
void InitializeTrace() override;
xe::ui::vulkan::VulkanDevice* device_ = nullptr;
// front buffer / back buffer memory
VkDeviceMemory fb_memory_ = nullptr;
VkImageView fb_image_view_ = nullptr;
VkFramebuffer fb_framebuffer_ = nullptr;
uint64_t dirty_float_constants_ = 0; // Dirty float constants in blocks of 4
uint8_t dirty_bool_constants_ = 0;
uint32_t dirty_loop_constants_ = 0;
@@ -114,14 +108,6 @@ class VulkanCommandProcessor : public CommandProcessor {
uint32_t coher_base_vc_ = 0;
uint32_t coher_size_vc_ = 0;
// TODO(benvanik): abstract behind context?
// Queue used to submit work. This may be a dedicated queue for the command
// processor and no locking will be required for use. If a dedicated queue
// was not available this will be the device primary_queue and the
// queue_mutex must be used to synchronize access to it.
VkQueue queue_ = nullptr;
std::mutex* queue_mutex_ = nullptr;
// Last copy base address, for debugging only.
uint32_t last_copy_base_ = 0;
@@ -142,6 +128,10 @@ class VulkanCommandProcessor : public CommandProcessor {
VkCommandBuffer current_command_buffer_ = nullptr;
VkCommandBuffer current_setup_buffer_ = nullptr;
VkFence current_batch_fence_;
ui::vulkan::VulkanSubmissionTracker swap_submission_tracker_;
VkFramebuffer swap_framebuffer_ = VK_NULL_HANDLE;
uint64_t swap_framebuffer_version_ = UINT64_MAX;
};
} // namespace vulkan

View File

@@ -2,267 +2,32 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2016 Ben Vanik. All rights reserved. *
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include <algorithm>
#include <cstring>
#include "xenia/base/logging.h"
#include "xenia/base/profiling.h"
#include "xenia/cpu/processor.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/vulkan/vulkan_gpu_flags.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include "xenia/ui/vulkan/vulkan_swap_chain.h"
#include "xenia/ui/vulkan/vulkan_util.h"
#include "xenia/ui/window.h"
#include "xenia/xbox.h"
namespace xe {
namespace gpu {
namespace vulkan {
using xe::ui::RawImage;
using xe::ui::vulkan::CheckResult;
VulkanGraphicsSystem::VulkanGraphicsSystem() {}
VulkanGraphicsSystem::~VulkanGraphicsSystem() = default;
VulkanGraphicsSystem::~VulkanGraphicsSystem() {}
X_STATUS VulkanGraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state,
ui::Window* target_window) {
// Must create the provider so we can create contexts.
auto provider = xe::ui::vulkan::VulkanProvider::Create();
device_ = provider->device();
provider_ = std::move(provider);
auto result = GraphicsSystem::Setup(processor, kernel_state, target_window);
if (result) {
return result;
}
if (target_window) {
display_context_ = reinterpret_cast<xe::ui::vulkan::VulkanContext*>(
target_window->context());
}
// Create our own command pool we can use for captures.
VkCommandPoolCreateInfo create_info = {
VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
nullptr,
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT |
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
device_->queue_family_index(),
};
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
auto status =
dfn.vkCreateCommandPool(*device_, &create_info, nullptr, &command_pool_);
CheckResult(status, "vkCreateCommandPool");
return X_STATUS_SUCCESS;
}
void VulkanGraphicsSystem::Shutdown() {
GraphicsSystem::Shutdown();
if (command_pool_ != VK_NULL_HANDLE) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkDestroyCommandPool(*device_, command_pool_, nullptr);
command_pool_ = VK_NULL_HANDLE;
}
}
std::unique_ptr<RawImage> VulkanGraphicsSystem::Capture() {
auto& swap_state = command_processor_->swap_state();
std::lock_guard<std::mutex> lock(swap_state.mutex);
if (!swap_state.front_buffer_texture) {
return nullptr;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
VkResult status = VK_SUCCESS;
VkCommandBufferAllocateInfo alloc_info = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
nullptr,
command_pool_,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1,
};
VkCommandBuffer cmd = nullptr;
status = dfn.vkAllocateCommandBuffers(*device_, &alloc_info, &cmd);
CheckResult(status, "vkAllocateCommandBuffers");
if (status != VK_SUCCESS) {
return nullptr;
}
VkCommandBufferBeginInfo begin_info = {
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
nullptr,
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
nullptr,
};
dfn.vkBeginCommandBuffer(cmd, &begin_info);
auto front_buffer =
reinterpret_cast<VkImage>(swap_state.front_buffer_texture);
status = CreateCaptureBuffer(cmd, {swap_state.width, swap_state.height});
if (status != VK_SUCCESS) {
dfn.vkFreeCommandBuffers(*device_, command_pool_, 1, &cmd);
return nullptr;
}
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = front_buffer;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
dfn.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
// Copy front buffer into capture image.
VkBufferImageCopy region = {
0, 0,
0, {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
{0, 0, 0}, {swap_state.width, swap_state.height, 1},
};
dfn.vkCmdCopyImageToBuffer(cmd, front_buffer, VK_IMAGE_LAYOUT_GENERAL,
capture_buffer_, 1, &region);
VkBufferMemoryBarrier memory_barrier = {
VK_STRUCTURE_TYPE_MEMORY_BARRIER,
nullptr,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_READ_BIT,
VK_QUEUE_FAMILY_IGNORED,
VK_QUEUE_FAMILY_IGNORED,
capture_buffer_,
0,
VK_WHOLE_SIZE,
};
dfn.vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr,
1, &memory_barrier, 0, nullptr);
status = dfn.vkEndCommandBuffer(cmd);
// Submit commands and wait.
if (status == VK_SUCCESS) {
std::lock_guard<std::mutex> lock(device_->primary_queue_mutex());
VkSubmitInfo submit_info = {
VK_STRUCTURE_TYPE_SUBMIT_INFO,
nullptr,
0,
nullptr,
nullptr,
1,
&cmd,
0,
nullptr,
};
status =
dfn.vkQueueSubmit(device_->primary_queue(), 1, &submit_info, nullptr);
CheckResult(status, "vkQueueSubmit");
if (status == VK_SUCCESS) {
status = dfn.vkQueueWaitIdle(device_->primary_queue());
CheckResult(status, "vkQueueWaitIdle");
}
}
dfn.vkFreeCommandBuffers(*device_, command_pool_, 1, &cmd);
void* data;
if (status == VK_SUCCESS) {
status = dfn.vkMapMemory(*device_, capture_buffer_memory_, 0, VK_WHOLE_SIZE,
0, &data);
CheckResult(status, "vkMapMemory");
}
if (status == VK_SUCCESS) {
std::unique_ptr<RawImage> raw_image(new RawImage());
raw_image->width = swap_state.width;
raw_image->height = swap_state.height;
raw_image->stride = swap_state.width * 4;
raw_image->data.resize(raw_image->stride * raw_image->height);
std::memcpy(raw_image->data.data(), data,
raw_image->stride * raw_image->height);
dfn.vkUnmapMemory(*device_, capture_buffer_memory_);
DestroyCaptureBuffer();
return raw_image;
}
DestroyCaptureBuffer();
return nullptr;
}
VkResult VulkanGraphicsSystem::CreateCaptureBuffer(VkCommandBuffer cmd,
VkExtent2D extents) {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
VkResult status = VK_SUCCESS;
VkBufferCreateInfo buffer_info = {
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
nullptr,
0,
extents.width * extents.height * 4,
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_SHARING_MODE_EXCLUSIVE,
0,
nullptr,
};
status =
dfn.vkCreateBuffer(*device_, &buffer_info, nullptr, &capture_buffer_);
if (status != VK_SUCCESS) {
return status;
}
capture_buffer_size_ = extents.width * extents.height * 4;
// Bind memory to buffer.
VkMemoryRequirements mem_requirements;
dfn.vkGetBufferMemoryRequirements(*device_, capture_buffer_,
&mem_requirements);
capture_buffer_memory_ = device_->AllocateMemory(
mem_requirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
assert_not_null(capture_buffer_memory_);
status = dfn.vkBindBufferMemory(*device_, capture_buffer_,
capture_buffer_memory_, 0);
CheckResult(status, "vkBindImageMemory");
if (status != VK_SUCCESS) {
dfn.vkDestroyBuffer(*device_, capture_buffer_, nullptr);
return status;
}
return status;
}
void VulkanGraphicsSystem::DestroyCaptureBuffer() {
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
dfn.vkDestroyBuffer(*device_, capture_buffer_, nullptr);
dfn.vkFreeMemory(*device_, capture_buffer_memory_, nullptr);
capture_buffer_ = nullptr;
capture_buffer_memory_ = nullptr;
capture_buffer_size_ = 0;
ui::WindowedAppContext* app_context,
bool is_surface_required) {
provider_ = xe::ui::vulkan::VulkanProvider::Create(is_surface_required);
return GraphicsSystem::Setup(processor, kernel_state, app_context,
is_surface_required);
}
std::unique_ptr<CommandProcessor>
@@ -270,71 +35,6 @@ VulkanGraphicsSystem::CreateCommandProcessor() {
return std::make_unique<VulkanCommandProcessor>(this, kernel_state_);
}
void VulkanGraphicsSystem::Swap(xe::ui::UIEvent* e) {
if (!command_processor_ || !display_context_) {
return;
}
// Check for pending swap.
auto& swap_state = command_processor_->swap_state();
if (display_context_->WasLost()) {
// We're crashing. Cheese it.
swap_state.pending = false;
return;
}
{
std::lock_guard<std::mutex> lock(swap_state.mutex);
if (!swap_state.pending) {
// return;
}
swap_state.pending = false;
}
if (!swap_state.front_buffer_texture) {
// Not yet ready.
return;
}
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device_->dfn();
auto swap_chain = display_context_->swap_chain();
auto copy_cmd_buffer = swap_chain->copy_cmd_buffer();
auto front_buffer =
reinterpret_cast<VkImage>(swap_state.front_buffer_texture);
VkImageMemoryBarrier barrier;
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = front_buffer;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
dfn.vkCmdPipelineBarrier(copy_cmd_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
VkImageBlit region;
region.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.srcOffsets[0] = {0, 0, 0};
region.srcOffsets[1] = {static_cast<int32_t>(swap_state.width),
static_cast<int32_t>(swap_state.height), 1};
region.dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1};
region.dstOffsets[0] = {0, 0, 0};
region.dstOffsets[1] = {static_cast<int32_t>(swap_chain->surface_width()),
static_cast<int32_t>(swap_chain->surface_height()),
1};
dfn.vkCmdBlitImage(copy_cmd_buffer, front_buffer, VK_IMAGE_LAYOUT_GENERAL,
swap_chain->surface_image(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region,
VK_FILTER_LINEAR);
}
} // namespace vulkan
} // namespace gpu
} // namespace xe

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -12,8 +12,8 @@
#include <memory>
#include "xenia/gpu/command_processor.h"
#include "xenia/gpu/graphics_system.h"
#include "xenia/ui/vulkan/vulkan_context.h"
namespace xe {
namespace gpu {
@@ -29,26 +29,11 @@ class VulkanGraphicsSystem : public GraphicsSystem {
std::string name() const override { return "Vulkan - obsolete"; }
X_STATUS Setup(cpu::Processor* processor, kernel::KernelState* kernel_state,
ui::Window* target_window) override;
void Shutdown() override;
std::unique_ptr<xe::ui::RawImage> Capture() override;
ui::WindowedAppContext* app_context,
bool is_surface_required) override;
private:
VkResult CreateCaptureBuffer(VkCommandBuffer cmd, VkExtent2D extents);
void DestroyCaptureBuffer();
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
void Swap(xe::ui::UIEvent* e) override;
xe::ui::vulkan::VulkanDevice* device_ = nullptr;
xe::ui::vulkan::VulkanContext* display_context_ = nullptr;
VkCommandPool command_pool_ = nullptr;
VkBuffer capture_buffer_ = nullptr;
VkDeviceMemory capture_buffer_memory_ = nullptr;
VkDeviceSize capture_buffer_size_ = 0;
};
} // namespace vulkan

View File

@@ -13,26 +13,27 @@
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe {
namespace gpu {
namespace vulkan {
using xe::ui::vulkan::CheckResult;
using xe::ui::vulkan::util::CheckResult;
VulkanShader::VulkanShader(ui::vulkan::VulkanDevice* device,
VulkanShader::VulkanShader(const ui::vulkan::VulkanProvider& provider,
xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count)
: Shader(shader_type, data_hash, dword_ptr, dword_count), device_(device) {}
: Shader(shader_type, data_hash, dword_ptr, dword_count),
provider_(provider) {}
VulkanShader::VulkanTranslation::~VulkanTranslation() {
if (shader_module_) {
const VulkanShader& vulkan_shader = static_cast<VulkanShader&>(shader());
const ui::vulkan::VulkanDevice* device = vulkan_shader.device_;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device->dfn();
dfn.vkDestroyShaderModule(*device, shader_module_, nullptr);
const ui::vulkan::VulkanProvider& provider =
static_cast<VulkanShader&>(shader()).provider_;
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
dfn.vkDestroyShaderModule(device, shader_module_, nullptr);
shader_module_ = nullptr;
}
}
@@ -42,8 +43,9 @@ bool VulkanShader::VulkanTranslation::Prepare() {
assert_true(is_valid());
const VulkanShader& vulkan_shader = static_cast<VulkanShader&>(shader());
const ui::vulkan::VulkanDevice* device = vulkan_shader.device_;
const ui::vulkan::VulkanDevice::DeviceFunctions& dfn = device->dfn();
const ui::vulkan::VulkanProvider& provider = vulkan_shader.provider_;
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
VkDevice device = provider.device();
// Create the shader module.
VkShaderModuleCreateInfo shader_info;
@@ -54,7 +56,7 @@ bool VulkanShader::VulkanTranslation::Prepare() {
shader_info.pCode =
reinterpret_cast<const uint32_t*>(translated_binary().data());
auto status =
dfn.vkCreateShaderModule(*device, &shader_info, nullptr, &shader_module_);
dfn.vkCreateShaderModule(device, &shader_info, nullptr, &shader_module_);
CheckResult(status, "vkCreateShaderModule");
char type_char;
@@ -68,10 +70,10 @@ bool VulkanShader::VulkanTranslation::Prepare() {
default:
type_char = 'u';
}
device->DbgSetObjectName(uint64_t(shader_module_),
VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
fmt::format("S({}): {:016X}", type_char,
vulkan_shader.ucode_data_hash()));
provider.SetDeviceObjectName(
VK_OBJECT_TYPE_SHADER_MODULE, uint64_t(shader_module_),
fmt::format("S({}): {:016X}", type_char, vulkan_shader.ucode_data_hash())
.c_str());
return status == VK_SUCCESS;
}

View File

@@ -13,7 +13,7 @@
#include <string>
#include "xenia/gpu/shader.h"
#include "xenia/ui/vulkan/vulkan_context.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
namespace gpu {
@@ -36,15 +36,15 @@ class VulkanShader : public Shader {
VkShaderModule shader_module_ = nullptr;
};
VulkanShader(ui::vulkan::VulkanDevice* device, xenos::ShaderType shader_type,
uint64_t data_hash, const uint32_t* dword_ptr,
uint32_t dword_count);
VulkanShader(const ui::vulkan::VulkanProvider& provider,
xenos::ShaderType shader_type, uint64_t data_hash,
const uint32_t* dword_ptr, uint32_t dword_count);
protected:
Translation* CreateTranslationInstance(uint64_t modification) override;
private:
ui::vulkan::VulkanDevice* device_ = nullptr;
const ui::vulkan::VulkanProvider& provider_;
};
} // namespace vulkan

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2022 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -12,7 +12,6 @@
#include "xenia/gpu/trace_dump.h"
#include "xenia/gpu/vulkan/vulkan_command_processor.h"
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
#include "xenia/ui/vulkan/vulkan_device.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
namespace xe {
@@ -28,20 +27,24 @@ class VulkanTraceDump : public TraceDump {
}
void BeginHostCapture() override {
auto device = static_cast<const ui::vulkan::VulkanProvider*>(
graphics_system_->provider())
->device();
if (device->is_renderdoc_attached()) {
device->BeginRenderDocFrameCapture();
const RENDERDOC_API_1_0_0* renderdoc_api =
static_cast<const ui::vulkan::VulkanProvider*>(
graphics_system_->provider())
->renderdoc_api()
.api_1_0_0();
if (renderdoc_api && !renderdoc_api->IsFrameCapturing()) {
renderdoc_api->StartFrameCapture(nullptr, nullptr);
}
}
void EndHostCapture() override {
auto device = static_cast<const ui::vulkan::VulkanProvider*>(
graphics_system_->provider())
->device();
if (device->is_renderdoc_attached()) {
device->EndRenderDocFrameCapture();
const RENDERDOC_API_1_0_0* renderdoc_api =
static_cast<const ui::vulkan::VulkanProvider*>(
graphics_system_->provider())
->renderdoc_api()
.api_1_0_0();
if (renderdoc_api && renderdoc_api->IsFrameCapturing()) {
renderdoc_api->EndFrameCapture(nullptr, nullptr);
}
}
};

View File

@@ -36,7 +36,7 @@ class VulkanTraceViewer final : public TraceViewer {
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
xenos::ColorRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
graphics_system()->command_processor());
// return command_processor->GetColorRenderTarget(pitch, samples, base,
// format);
return 0;
@@ -46,7 +46,7 @@ class VulkanTraceViewer final : public TraceViewer {
uint32_t pitch, xenos::MsaaSamples samples, uint32_t base,
xenos::DepthRenderTargetFormat format) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
graphics_system()->command_processor());
// return command_processor->GetDepthRenderTarget(pitch, samples, base,
// format);
return 0;
@@ -55,7 +55,7 @@ class VulkanTraceViewer final : public TraceViewer {
uintptr_t GetTextureEntry(const TextureInfo& texture_info,
const SamplerInfo& sampler_info) override {
auto command_processor = static_cast<VulkanCommandProcessor*>(
graphics_system_->command_processor());
graphics_system()->command_processor());
// auto entry_view =
// command_processor->texture_cache()->Demand(texture_info,