[Vulkan] Use a swap chain for the backend
This commit is contained in:
parent
3fcdbefce8
commit
e309e6ce6d
|
@ -49,7 +49,8 @@ class VulkanRenderer : public QVulkanWindowRenderer {
|
||||||
auto swap_state = graphics_system_->swap_state();
|
auto swap_state = graphics_system_->swap_state();
|
||||||
|
|
||||||
auto cmd = window_->currentCommandBuffer();
|
auto cmd = window_->currentCommandBuffer();
|
||||||
auto src = reinterpret_cast<VkImage>(swap_state->front_buffer_texture);
|
auto src = reinterpret_cast<VkImage>(
|
||||||
|
swap_state->buffer_textures[swap_state->current_buffer]);
|
||||||
auto dest = window_->swapChainImage(window_->currentSwapChainImageIndex());
|
auto dest = window_->swapChainImage(window_->currentSwapChainImageIndex());
|
||||||
auto dest_size = window_->swapChainImageSize();
|
auto dest_size = window_->swapChainImageSize();
|
||||||
|
|
||||||
|
|
|
@ -28,18 +28,18 @@ class Emulator;
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
|
const uint32_t kNumSwapBuffers = 2;
|
||||||
|
|
||||||
struct SwapState {
|
struct SwapState {
|
||||||
// Lock must be held when changing data in this structure.
|
// Lock must be held when changing data in this structure.
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
// Dimensions of the framebuffer textures. Should match window size.
|
// Dimensions of the framebuffer textures. Should match window size.
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
// Current front buffer, being drawn to the screen.
|
// Array of swap textures.
|
||||||
uintptr_t front_buffer_texture = 0;
|
uintptr_t buffer_textures[kNumSwapBuffers];
|
||||||
// Current back buffer, being updated by the CP.
|
// Current swap buffer index
|
||||||
uintptr_t back_buffer_texture = 0;
|
size_t current_buffer = 0;
|
||||||
// Backend data
|
|
||||||
void* backend_data = nullptr;
|
|
||||||
// Whether the back buffer is dirty and a swap is pending.
|
// Whether the back buffer is dirty and a swap is pending.
|
||||||
bool pending = false;
|
bool pending = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -226,12 +226,25 @@ void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
|
||||||
|
|
||||||
void VulkanCommandProcessor::BeginFrame() {
|
void VulkanCommandProcessor::BeginFrame() {
|
||||||
assert_false(frame_open_);
|
assert_false(frame_open_);
|
||||||
|
VkResult status = VK_SUCCESS;
|
||||||
|
|
||||||
|
// Grab a fence from the backbuffer.
|
||||||
|
auto swap_state =
|
||||||
|
reinterpret_cast<VulkanGraphicsSystem*>(graphics_system_)->swap_state();
|
||||||
|
auto& swap_resources =
|
||||||
|
swap_state->buffer_resources[(swap_state->current_buffer + 1) %
|
||||||
|
kNumSwapBuffers];
|
||||||
|
|
||||||
|
// Wait for the fence, in-case it's still in-use by the GPU.
|
||||||
|
status = vkWaitForFences(*device_, 1, &swap_resources.buf_fence, VK_TRUE, -1);
|
||||||
|
vkResetFences(*device_, 1, &swap_resources.buf_fence);
|
||||||
|
|
||||||
// TODO(benvanik): bigger batches.
|
// TODO(benvanik): bigger batches.
|
||||||
// TODO(DrChat): Decouple setup buffer from current batch.
|
// TODO(DrChat): Decouple setup buffer from current batch.
|
||||||
// Begin a new batch, and allocate and begin a command buffer and setup
|
// Begin a new batch, and allocate and begin a command buffer and setup
|
||||||
// buffer.
|
// buffer.
|
||||||
current_batch_fence_ = command_buffer_pool_->BeginBatch();
|
current_batch_fence_ =
|
||||||
|
command_buffer_pool_->BeginBatch(swap_resources.buf_fence);
|
||||||
current_command_buffer_ = command_buffer_pool_->AcquireEntry();
|
current_command_buffer_ = command_buffer_pool_->AcquireEntry();
|
||||||
current_setup_buffer_ = command_buffer_pool_->AcquireEntry();
|
current_setup_buffer_ = command_buffer_pool_->AcquireEntry();
|
||||||
|
|
||||||
|
@ -240,7 +253,7 @@ void VulkanCommandProcessor::BeginFrame() {
|
||||||
command_buffer_begin_info.pNext = nullptr;
|
command_buffer_begin_info.pNext = nullptr;
|
||||||
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
command_buffer_begin_info.pInheritanceInfo = nullptr;
|
command_buffer_begin_info.pInheritanceInfo = nullptr;
|
||||||
auto status =
|
status =
|
||||||
vkBeginCommandBuffer(current_command_buffer_, &command_buffer_begin_info);
|
vkBeginCommandBuffer(current_command_buffer_, &command_buffer_begin_info);
|
||||||
CheckResult(status, "vkBeginCommandBuffer");
|
CheckResult(status, "vkBeginCommandBuffer");
|
||||||
|
|
||||||
|
@ -293,19 +306,33 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
uint32_t frontbuffer_height) {
|
uint32_t frontbuffer_height) {
|
||||||
SCOPE_profile_cpu_f("gpu");
|
SCOPE_profile_cpu_f("gpu");
|
||||||
|
|
||||||
|
auto swap_state =
|
||||||
|
reinterpret_cast<VulkanGraphicsSystem*>(graphics_system_)->swap_state();
|
||||||
|
// Increment the current buffer.
|
||||||
|
swap_state->current_buffer =
|
||||||
|
(swap_state->current_buffer + 1) % kNumSwapBuffers;
|
||||||
|
|
||||||
|
auto& swap_resources =
|
||||||
|
swap_state->buffer_resources[swap_state->current_buffer];
|
||||||
|
|
||||||
// Build a final command buffer that copies the game's frontbuffer texture
|
// Build a final command buffer that copies the game's frontbuffer texture
|
||||||
// into our backbuffer texture.
|
// into our backbuffer texture.
|
||||||
VkCommandBuffer copy_commands = nullptr;
|
VkCommandBuffer copy_commands = nullptr;
|
||||||
bool opened_batch;
|
bool opened_batch = false;
|
||||||
if (command_buffer_pool_->has_open_batch()) {
|
if (!command_buffer_pool_->has_open_batch()) {
|
||||||
copy_commands = command_buffer_pool_->AcquireEntry();
|
// Wait for the fence, in-case it's still in-use by the GPU.
|
||||||
opened_batch = false;
|
auto status =
|
||||||
} else {
|
vkWaitForFences(*device_, 1, &swap_resources.buf_fence, VK_TRUE, -1);
|
||||||
current_batch_fence_ = command_buffer_pool_->BeginBatch();
|
vkResetFences(*device_, 1, &swap_resources.buf_fence);
|
||||||
copy_commands = command_buffer_pool_->AcquireEntry();
|
|
||||||
|
// We'll have to open a batch if there isn't one open.
|
||||||
|
current_batch_fence_ =
|
||||||
|
command_buffer_pool_->BeginBatch(swap_resources.buf_fence);
|
||||||
opened_batch = true;
|
opened_batch = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy_commands = command_buffer_pool_->AcquireEntry();
|
||||||
|
|
||||||
VkCommandBufferBeginInfo begin_info;
|
VkCommandBufferBeginInfo begin_info;
|
||||||
std::memset(&begin_info, 0, sizeof(begin_info));
|
std::memset(&begin_info, 0, sizeof(begin_info));
|
||||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
@ -318,29 +345,27 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
frontbuffer_ptr = last_copy_base_;
|
frontbuffer_ptr = last_copy_base_;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto swap_state =
|
|
||||||
reinterpret_cast<VulkanGraphicsSystem*>(graphics_system_)->swap_state();
|
|
||||||
|
|
||||||
// Create a framebuffer if it isn't already created.
|
// Create a framebuffer if it isn't already created.
|
||||||
if (!swap_state->fb_framebuffer_) {
|
if (!swap_resources.buf_framebuffer) {
|
||||||
VkFramebufferCreateInfo framebuffer_create_info = {
|
VkFramebufferCreateInfo framebuffer_create_info = {
|
||||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
nullptr,
|
nullptr,
|
||||||
0,
|
0,
|
||||||
blitter_->GetRenderPass(VK_FORMAT_R8G8B8A8_UNORM, true),
|
blitter_->GetRenderPass(VK_FORMAT_R8G8B8A8_UNORM, true),
|
||||||
1,
|
1,
|
||||||
&swap_state->fb_image_view_,
|
&swap_resources.buf_image_view,
|
||||||
swap_state->width,
|
swap_state->width,
|
||||||
swap_state->height,
|
swap_state->height,
|
||||||
1,
|
1,
|
||||||
};
|
};
|
||||||
status = vkCreateFramebuffer(*device_, &framebuffer_create_info, nullptr,
|
status = vkCreateFramebuffer(*device_, &framebuffer_create_info, nullptr,
|
||||||
&swap_state->fb_framebuffer_);
|
&swap_resources.buf_framebuffer);
|
||||||
CheckResult(status, "vkCreateFramebuffer");
|
CheckResult(status, "vkCreateFramebuffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto swap_fb = reinterpret_cast<VkImage>(swap_state->front_buffer_texture);
|
auto swap_fb = reinterpret_cast<VkImage>(
|
||||||
if (swap_state->fb_image_layout_ == VK_IMAGE_LAYOUT_UNDEFINED) {
|
swap_state->buffer_textures[swap_state->current_buffer]);
|
||||||
|
if (swap_resources.buf_image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
// Transition image to general layout.
|
// Transition image to general layout.
|
||||||
VkImageMemoryBarrier barrier;
|
VkImageMemoryBarrier barrier;
|
||||||
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
|
std::memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
|
||||||
|
@ -359,6 +384,7 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
nullptr, 0, nullptr, 1, &barrier);
|
nullptr, 0, nullptr, 1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the game's frontbuffer from a fetch constant populated by VdSwap.
|
||||||
auto& regs = *register_file_;
|
auto& regs = *register_file_;
|
||||||
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0;
|
int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0;
|
||||||
auto group =
|
auto group =
|
||||||
|
@ -395,6 +421,7 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr,
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr,
|
||||||
0, nullptr, 1, &barrier);
|
0, nullptr, 1, &barrier);
|
||||||
|
|
||||||
|
// Notify the GPU we're gonna write to the swap image.
|
||||||
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||||
|
@ -422,7 +449,7 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
texture_cache_->DemandView(texture, 0x688)->view, src_rect,
|
texture_cache_->DemandView(texture, 0x688)->view, src_rect,
|
||||||
{texture->texture_info.width + 1, texture->texture_info.height + 1},
|
{texture->texture_info.width + 1, texture->texture_info.height + 1},
|
||||||
VK_FORMAT_R8G8B8A8_UNORM, dst_rect,
|
VK_FORMAT_R8G8B8A8_UNORM, dst_rect,
|
||||||
{frontbuffer_width, frontbuffer_height}, swap_state->fb_framebuffer_,
|
{frontbuffer_width, frontbuffer_height}, swap_resources.buf_framebuffer,
|
||||||
viewport, scissor, VK_FILTER_LINEAR, true, true);
|
viewport, scissor, VK_FILTER_LINEAR, true, true);
|
||||||
|
|
||||||
std::swap(barrier.oldLayout, barrier.newLayout);
|
std::swap(barrier.oldLayout, barrier.newLayout);
|
||||||
|
@ -485,8 +512,8 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vkWaitForFences(*device_, 1, ¤t_batch_fence_, VK_TRUE, -1);
|
|
||||||
if (cache_clear_requested_) {
|
if (cache_clear_requested_) {
|
||||||
|
vkWaitForFences(*device_, 1, ¤t_batch_fence_, VK_TRUE, -1);
|
||||||
cache_clear_requested_ = false;
|
cache_clear_requested_ = false;
|
||||||
|
|
||||||
buffer_cache_->ClearCache();
|
buffer_cache_->ClearCache();
|
||||||
|
|
|
@ -33,6 +33,7 @@ VulkanGraphicsSystem::~VulkanGraphicsSystem() = default;
|
||||||
X_STATUS VulkanGraphicsSystem::Setup(
|
X_STATUS VulkanGraphicsSystem::Setup(
|
||||||
cpu::Processor* processor, kernel::KernelState* kernel_state,
|
cpu::Processor* processor, kernel::KernelState* kernel_state,
|
||||||
std::unique_ptr<ui::GraphicsContext> context) {
|
std::unique_ptr<ui::GraphicsContext> context) {
|
||||||
|
VkResult status;
|
||||||
device_ = static_cast<ui::vulkan::VulkanContext*>(context.get())->device();
|
device_ = static_cast<ui::vulkan::VulkanContext*>(context.get())->device();
|
||||||
|
|
||||||
auto result =
|
auto result =
|
||||||
|
@ -49,28 +50,33 @@ X_STATUS VulkanGraphicsSystem::Setup(
|
||||||
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||||
device_->queue_family_index(),
|
device_->queue_family_index(),
|
||||||
};
|
};
|
||||||
auto status =
|
status = vkCreateCommandPool(*device_, &create_info, nullptr, &command_pool_);
|
||||||
vkCreateCommandPool(*device_, &create_info, nullptr, &command_pool_);
|
|
||||||
CheckResult(status, "vkCreateCommandPool");
|
CheckResult(status, "vkCreateCommandPool");
|
||||||
|
|
||||||
// TODO(DrChat): Don't hardcode this resolution.
|
for (uint32_t i = 0; i < kNumSwapBuffers; i++) {
|
||||||
CreateSwapImage({1280, 720});
|
// TODO(DrChat): Don't hardcode this resolution.
|
||||||
|
status = CreateSwapImage({1280, 720}, &swap_state_.buffer_textures[i],
|
||||||
|
&swap_state_.buffer_resources[i]);
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanGraphicsSystem::Shutdown() {
|
void VulkanGraphicsSystem::Shutdown() {
|
||||||
GraphicsSystem::Shutdown();
|
GraphicsSystem::Shutdown();
|
||||||
|
|
||||||
DestroySwapImage();
|
for (uint32_t i = 0; i < kNumSwapBuffers; i++) {
|
||||||
|
DestroySwapImage(&swap_state_.buffer_textures[i],
|
||||||
|
&swap_state_.buffer_resources[i]);
|
||||||
|
}
|
||||||
VK_SAFE_DESTROY(vkDestroyCommandPool, *device_, command_pool_, nullptr);
|
VK_SAFE_DESTROY(vkDestroyCommandPool, *device_, command_pool_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RawImage> VulkanGraphicsSystem::Capture() {
|
std::unique_ptr<RawImage> VulkanGraphicsSystem::Capture() {
|
||||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
||||||
if (!swap_state_.front_buffer_texture) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult status = VK_SUCCESS;
|
VkResult status = VK_SUCCESS;
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo alloc_info = {
|
VkCommandBufferAllocateInfo alloc_info = {
|
||||||
|
@ -96,8 +102,8 @@ std::unique_ptr<RawImage> VulkanGraphicsSystem::Capture() {
|
||||||
};
|
};
|
||||||
vkBeginCommandBuffer(cmd, &begin_info);
|
vkBeginCommandBuffer(cmd, &begin_info);
|
||||||
|
|
||||||
auto front_buffer =
|
auto front_buffer = reinterpret_cast<VkImage>(
|
||||||
reinterpret_cast<VkImage>(swap_state_.front_buffer_texture);
|
swap_state_.buffer_textures[swap_state_.current_buffer]);
|
||||||
|
|
||||||
status = CreateCaptureBuffer(cmd, {swap_state_.width, swap_state_.height});
|
status = CreateCaptureBuffer(cmd, {swap_state_.width, swap_state_.height});
|
||||||
if (status != VK_SUCCESS) {
|
if (status != VK_SUCCESS) {
|
||||||
|
@ -246,7 +252,19 @@ void VulkanGraphicsSystem::DestroyCaptureBuffer() {
|
||||||
capture_buffer_size_ = 0;
|
capture_buffer_size_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanGraphicsSystem::CreateSwapImage(VkExtent2D extents) {
|
VkResult VulkanGraphicsSystem::CreateSwapImage(
|
||||||
|
VkExtent2D extents, uintptr_t* image_out,
|
||||||
|
SwapState::BufferResources* buffer_resources) {
|
||||||
|
VkResult status;
|
||||||
|
|
||||||
|
VkFenceCreateInfo fence_info = {
|
||||||
|
VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||||
|
nullptr,
|
||||||
|
VK_FENCE_CREATE_SIGNALED_BIT,
|
||||||
|
};
|
||||||
|
status = vkCreateFence(*device_, &fence_info, nullptr,
|
||||||
|
&buffer_resources->buf_fence);
|
||||||
|
|
||||||
VkImageCreateInfo image_info;
|
VkImageCreateInfo image_info;
|
||||||
std::memset(&image_info, 0, sizeof(VkImageCreateInfo));
|
std::memset(&image_info, 0, sizeof(VkImageCreateInfo));
|
||||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
@ -264,29 +282,37 @@ void VulkanGraphicsSystem::CreateSwapImage(VkExtent2D extents) {
|
||||||
image_info.pQueueFamilyIndices = nullptr;
|
image_info.pQueueFamilyIndices = nullptr;
|
||||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
VkImage image_fb;
|
VkImage image_buf;
|
||||||
auto status = vkCreateImage(*device_, &image_info, nullptr, &image_fb);
|
status = vkCreateImage(*device_, &image_info, nullptr, &image_buf);
|
||||||
CheckResult(status, "vkCreateImage");
|
CheckResult(status, "vkCreateImage");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
// Bind memory to image.
|
// Bind memory to image.
|
||||||
VkMemoryRequirements mem_requirements;
|
VkMemoryRequirements mem_requirements;
|
||||||
vkGetImageMemoryRequirements(*device_, image_fb, &mem_requirements);
|
vkGetImageMemoryRequirements(*device_, image_buf, &mem_requirements);
|
||||||
swap_state_.fb_memory_ = device_->AllocateMemory(mem_requirements, 0);
|
buffer_resources->buf_memory = device_->AllocateMemory(mem_requirements, 0);
|
||||||
assert_not_null(swap_state_.fb_memory_);
|
assert_not_null(buffer_resources->buf_memory);
|
||||||
|
|
||||||
status = vkBindImageMemory(*device_, image_fb, swap_state_.fb_memory_, 0);
|
status =
|
||||||
|
vkBindImageMemory(*device_, image_buf, buffer_resources->buf_memory, 0);
|
||||||
CheckResult(status, "vkBindImageMemory");
|
CheckResult(status, "vkBindImageMemory");
|
||||||
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
||||||
swap_state_.front_buffer_texture = reinterpret_cast<uintptr_t>(image_fb);
|
*image_out = reinterpret_cast<uintptr_t>(image_buf);
|
||||||
swap_state_.width = extents.width;
|
swap_state_.width = extents.width;
|
||||||
swap_state_.height = extents.height;
|
swap_state_.height = extents.height;
|
||||||
|
buffer_resources->buf_image_layout = image_info.initialLayout;
|
||||||
|
|
||||||
VkImageViewCreateInfo view_create_info = {
|
VkImageViewCreateInfo view_create_info = {
|
||||||
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
nullptr,
|
nullptr,
|
||||||
0,
|
0,
|
||||||
image_fb,
|
image_buf,
|
||||||
VK_IMAGE_VIEW_TYPE_2D,
|
VK_IMAGE_VIEW_TYPE_2D,
|
||||||
VK_FORMAT_R8G8B8A8_UNORM,
|
VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
{VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
||||||
|
@ -294,25 +320,29 @@ void VulkanGraphicsSystem::CreateSwapImage(VkExtent2D extents) {
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
|
||||||
};
|
};
|
||||||
status = vkCreateImageView(*device_, &view_create_info, nullptr,
|
status = vkCreateImageView(*device_, &view_create_info, nullptr,
|
||||||
&swap_state_.fb_image_view_);
|
&buffer_resources->buf_image_view);
|
||||||
CheckResult(status, "vkCreateImageView");
|
CheckResult(status, "vkCreateImageView");
|
||||||
}
|
if (status != VK_SUCCESS) {
|
||||||
|
return status;
|
||||||
void VulkanGraphicsSystem::DestroySwapImage() {
|
|
||||||
VK_SAFE_DESTROY(vkDestroyFramebuffer, *device_, swap_state_.fb_framebuffer_,
|
|
||||||
nullptr);
|
|
||||||
VK_SAFE_DESTROY(vkDestroyImageView, *device_, swap_state_.fb_image_view_,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(swap_state_.mutex);
|
|
||||||
VK_SAFE_DESTROY(vkFreeMemory, *device_, swap_state_.fb_memory_, nullptr);
|
|
||||||
if (swap_state_.front_buffer_texture) {
|
|
||||||
vkDestroyImage(*device_,
|
|
||||||
reinterpret_cast<VkImage>(swap_state_.front_buffer_texture),
|
|
||||||
nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_state_.front_buffer_texture = 0;
|
return VK_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VulkanGraphicsSystem::DestroySwapImage(
|
||||||
|
uintptr_t* image, SwapState::BufferResources* buffer_resources) {
|
||||||
|
VK_SAFE_DESTROY(vkDestroyFence, *device_, buffer_resources->buf_fence,
|
||||||
|
nullptr);
|
||||||
|
VK_SAFE_DESTROY(vkDestroyFramebuffer, *device_,
|
||||||
|
buffer_resources->buf_framebuffer, nullptr);
|
||||||
|
VK_SAFE_DESTROY(vkDestroyImageView, *device_,
|
||||||
|
buffer_resources->buf_image_view, nullptr);
|
||||||
|
|
||||||
|
VK_SAFE_DESTROY(vkFreeMemory, *device_, buffer_resources->buf_memory,
|
||||||
|
nullptr);
|
||||||
|
if (image) {
|
||||||
|
vkDestroyImage(*device_, reinterpret_cast<VkImage>(image), nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<CommandProcessor>
|
std::unique_ptr<CommandProcessor>
|
||||||
|
|
|
@ -21,10 +21,13 @@ namespace vulkan {
|
||||||
|
|
||||||
struct SwapState : public gpu::SwapState {
|
struct SwapState : public gpu::SwapState {
|
||||||
// front buffer / back buffer memory
|
// front buffer / back buffer memory
|
||||||
VkDeviceMemory fb_memory_ = nullptr;
|
struct BufferResources {
|
||||||
VkImageView fb_image_view_ = nullptr;
|
VkDeviceMemory buf_memory = nullptr;
|
||||||
VkImageLayout fb_image_layout_ = VK_IMAGE_LAYOUT_UNDEFINED;
|
VkImageView buf_image_view = nullptr;
|
||||||
VkFramebuffer fb_framebuffer_ = nullptr; // Used and created by CP.
|
VkImageLayout buf_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
VkFramebuffer buf_framebuffer = nullptr; // Used and created by CP.
|
||||||
|
VkFence buf_fence = nullptr; // Completion fence. Used by CP.
|
||||||
|
} buffer_resources[kNumSwapBuffers];
|
||||||
};
|
};
|
||||||
|
|
||||||
class VulkanGraphicsSystem : public GraphicsSystem {
|
class VulkanGraphicsSystem : public GraphicsSystem {
|
||||||
|
@ -45,8 +48,10 @@ class VulkanGraphicsSystem : public GraphicsSystem {
|
||||||
VkResult CreateCaptureBuffer(VkCommandBuffer cmd, VkExtent2D extents);
|
VkResult CreateCaptureBuffer(VkCommandBuffer cmd, VkExtent2D extents);
|
||||||
void DestroyCaptureBuffer();
|
void DestroyCaptureBuffer();
|
||||||
|
|
||||||
void CreateSwapImage(VkExtent2D extents);
|
VkResult CreateSwapImage(VkExtent2D extents, uintptr_t* image_out,
|
||||||
void DestroySwapImage();
|
SwapState::BufferResources* buffer_resources);
|
||||||
|
void DestroySwapImage(uintptr_t* image,
|
||||||
|
SwapState::BufferResources* buffer_resources);
|
||||||
|
|
||||||
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
|
std::unique_ptr<CommandProcessor> CreateCommandProcessor() override;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue