[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:
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(®s.pa_sc_window_offset,
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
2
src/xenia/gpu/vulkan/shaders/bytecode/.clang-format
generated
Normal file
2
src/xenia/gpu/vulkan/shaders/bytecode/.clang-format
generated
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: false
|
||||
@@ -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,
|
||||
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/dummy_frag.spv
generated
Normal file
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/dummy_frag.spv
generated
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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,
|
||||
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/line_quad_list_geom.spv
generated
Normal file
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/line_quad_list_geom.spv
generated
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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,
|
||||
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/point_list_geom.spv
generated
Normal file
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/point_list_geom.spv
generated
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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,
|
||||
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/quad_list_geom.spv
generated
Normal file
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/quad_list_geom.spv
generated
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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,
|
||||
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/rect_list_geom.spv
generated
Normal file
BIN
src/xenia/gpu/vulkan/shaders/bytecode/vulkan_spirv/rect_list_geom.spv
generated
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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*>(®s.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*>(®s.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, ¤t_batch_fence_, VK_TRUE, -1);
|
||||
if (current_batch_fence_ != VK_NULL_HANDLE) {
|
||||
dfn.vkWaitForFences(device, 1, ¤t_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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ®ion);
|
||||
|
||||
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, ®ion,
|
||||
VK_FILTER_LINEAR);
|
||||
}
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace gpu
|
||||
} // namespace xe
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user