Vulkan: WIP Blitter
This commit is contained in:
parent
4fe6eba972
commit
e46a0c50fd
|
@ -0,0 +1,293 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/ui/vulkan/blitter.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace ui {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
// Generated with `xenia-build genspirv`.
|
||||||
|
#include "xenia/ui/vulkan/shaders/bin/blit_color_frag.h"
|
||||||
|
#include "xenia/ui/vulkan/shaders/bin/blit_depth_frag.h"
|
||||||
|
#include "xenia/ui/vulkan/shaders/bin/blit_vert.h"
|
||||||
|
|
||||||
|
Blitter::Blitter() {}
|
||||||
|
Blitter::~Blitter() {}
|
||||||
|
|
||||||
|
bool Blitter::Initialize(VulkanDevice* device) {
|
||||||
|
device_ = device;
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
VkShaderModuleCreateInfo shader_create_info;
|
||||||
|
std::memset(&shader_create_info, 0, sizeof(shader_create_info));
|
||||||
|
shader_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
|
shader_create_info.codeSize = sizeof(blit_vert);
|
||||||
|
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_vert);
|
||||||
|
auto result = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||||
|
&blit_vertex_);
|
||||||
|
CheckResult(result, "vkCreateShaderModule");
|
||||||
|
|
||||||
|
shader_create_info.codeSize = sizeof(blit_color_frag);
|
||||||
|
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_color_frag);
|
||||||
|
result = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||||
|
&blit_color_);
|
||||||
|
CheckResult(result, "vkCreateShaderModule");
|
||||||
|
|
||||||
|
shader_create_info.codeSize = sizeof(blit_depth_frag);
|
||||||
|
shader_create_info.pCode = reinterpret_cast<const uint32_t*>(blit_depth_frag);
|
||||||
|
result = vkCreateShaderModule(*device_, &shader_create_info, nullptr,
|
||||||
|
&blit_depth_);
|
||||||
|
CheckResult(result, "vkCreateShaderModule");
|
||||||
|
|
||||||
|
// Create the descriptor set layout used for our texture sampler.
|
||||||
|
// As it changes almost every draw we keep it separate from the uniform buffer
|
||||||
|
// and cache it on the textures.
|
||||||
|
VkDescriptorSetLayoutCreateInfo texture_set_layout_info;
|
||||||
|
texture_set_layout_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
texture_set_layout_info.pNext = nullptr;
|
||||||
|
texture_set_layout_info.flags = 0;
|
||||||
|
texture_set_layout_info.bindingCount = 1;
|
||||||
|
VkDescriptorSetLayoutBinding texture_binding;
|
||||||
|
texture_binding.binding = 0;
|
||||||
|
texture_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
texture_binding.descriptorCount = 1;
|
||||||
|
texture_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
texture_binding.pImmutableSamplers = nullptr;
|
||||||
|
texture_set_layout_info.pBindings = &texture_binding;
|
||||||
|
result = vkCreateDescriptorSetLayout(*device_, &texture_set_layout_info,
|
||||||
|
nullptr, &descriptor_set_layout_);
|
||||||
|
CheckResult(result, "vkCreateDescriptorSetLayout");
|
||||||
|
|
||||||
|
// Create the pipeline layout used for our pipeline.
|
||||||
|
// If we had multiple pipelines they would share this.
|
||||||
|
VkPipelineLayoutCreateInfo pipeline_layout_info;
|
||||||
|
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipeline_layout_info.pNext = nullptr;
|
||||||
|
pipeline_layout_info.flags = 0;
|
||||||
|
VkDescriptorSetLayout set_layouts[] = {descriptor_set_layout_};
|
||||||
|
pipeline_layout_info.setLayoutCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(set_layouts));
|
||||||
|
pipeline_layout_info.pSetLayouts = set_layouts;
|
||||||
|
VkPushConstantRange push_constant_ranges[2];
|
||||||
|
push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
push_constant_ranges[0].offset = 0;
|
||||||
|
push_constant_ranges[0].size = sizeof(float) * 16;
|
||||||
|
push_constant_ranges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
push_constant_ranges[1].offset = sizeof(float) * 16;
|
||||||
|
push_constant_ranges[1].size = sizeof(int);
|
||||||
|
pipeline_layout_info.pushConstantRangeCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(push_constant_ranges));
|
||||||
|
pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
|
||||||
|
result = vkCreatePipelineLayout(*device_, &pipeline_layout_info, nullptr,
|
||||||
|
&pipeline_layout_);
|
||||||
|
CheckResult(result, "vkCreatePipelineLayout");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::Shutdown() {
|
||||||
|
vkDestroyShaderModule(*device_, blit_vertex_, nullptr);
|
||||||
|
vkDestroyShaderModule(*device_, blit_color_, nullptr);
|
||||||
|
vkDestroyShaderModule(*device_, blit_depth_, nullptr);
|
||||||
|
vkDestroyPipeline(*device_, pipeline_color_, nullptr);
|
||||||
|
vkDestroyPipeline(*device_, pipeline_depth_, nullptr);
|
||||||
|
vkDestroyPipelineLayout(*device_, pipeline_layout_, nullptr);
|
||||||
|
vkDestroyDescriptorSetLayout(*device_, descriptor_set_layout_, nullptr);
|
||||||
|
vkDestroyRenderPass(*device_, render_pass_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Blitter::BlitTexture2D(VkCommandBuffer command_buffer, VkImage src_image,
|
||||||
|
VkImageView src_image_view, VkOffset2D src_offset,
|
||||||
|
VkExtent2D src_extents, VkImage dst_image,
|
||||||
|
VkImageView dst_image_view, VkFilter filter,
|
||||||
|
bool swap_channels) {}
|
||||||
|
|
||||||
|
void Blitter::CopyColorTexture2D(VkCommandBuffer command_buffer,
|
||||||
|
VkImage src_image, VkImageView src_image_view,
|
||||||
|
VkOffset2D src_offset, VkImage dst_image,
|
||||||
|
VkImageView dst_image_view, VkExtent2D extents,
|
||||||
|
VkFilter filter, bool swap_channels) {}
|
||||||
|
|
||||||
|
void Blitter::CopyDepthTexture(VkCommandBuffer command_buffer,
|
||||||
|
VkImage src_image, VkImageView src_image_view,
|
||||||
|
VkOffset2D src_offset, VkImage dst_image,
|
||||||
|
VkImageView dst_image_view, VkExtent2D extents) {
|
||||||
|
}
|
||||||
|
|
||||||
|
VkRenderPass Blitter::CreateRenderPass(VkFormat output_format) {
|
||||||
|
VkAttachmentDescription attachments[1];
|
||||||
|
std::memset(attachments, 0, sizeof(attachments));
|
||||||
|
|
||||||
|
// Output attachment
|
||||||
|
// TODO(DrChat): Figure out a way to leave the format undefined here.
|
||||||
|
attachments[0].format = output_format;
|
||||||
|
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
|
attachments[0].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
attachments[0].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
|
||||||
|
VkSubpassDescription subpass;
|
||||||
|
std::memset(&subpass, 0, sizeof(subpass));
|
||||||
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||||
|
|
||||||
|
VkAttachmentReference attach_refs[1];
|
||||||
|
attach_refs[0].attachment = 0;
|
||||||
|
attach_refs[0].layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
subpass.colorAttachmentCount = 1;
|
||||||
|
subpass.pColorAttachments = attach_refs;
|
||||||
|
|
||||||
|
VkRenderPassCreateInfo renderpass;
|
||||||
|
std::memset(&renderpass, 0, sizeof(renderpass));
|
||||||
|
renderpass.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||||
|
renderpass.attachmentCount = 1;
|
||||||
|
renderpass.pAttachments = attachments;
|
||||||
|
renderpass.subpassCount = 1;
|
||||||
|
renderpass.pSubpasses = &subpass;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPipeline Blitter::CreatePipeline(VkRenderPass render_pass) {
|
||||||
|
// Pipeline
|
||||||
|
VkGraphicsPipelineCreateInfo pipeline_info;
|
||||||
|
std::memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));
|
||||||
|
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
|
||||||
|
// Shaders
|
||||||
|
pipeline_info.stageCount = 2;
|
||||||
|
VkPipelineShaderStageCreateInfo stages[2];
|
||||||
|
std::memset(stages, 0, sizeof(stages));
|
||||||
|
stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
stages[0].module = blit_vertex_;
|
||||||
|
stages[0].pName = "main";
|
||||||
|
stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
stages[1].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
stages[1].module = blit_color_;
|
||||||
|
stages[1].pName = "main";
|
||||||
|
|
||||||
|
// Vertex input
|
||||||
|
VkPipelineVertexInputStateCreateInfo vtx_state;
|
||||||
|
std::memset(&vtx_state, 0, sizeof(vtx_state));
|
||||||
|
vtx_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription bindings[1];
|
||||||
|
VkVertexInputAttributeDescription attribs[1];
|
||||||
|
bindings[0].binding = 0;
|
||||||
|
bindings[0].stride = 8;
|
||||||
|
bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|
||||||
|
attribs[0].location = 0;
|
||||||
|
attribs[0].binding = 0;
|
||||||
|
attribs[0].format = VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
attribs[0].offset = 0;
|
||||||
|
|
||||||
|
pipeline_info.pVertexInputState = &vtx_state;
|
||||||
|
|
||||||
|
// Input Assembly
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo input_info;
|
||||||
|
input_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
input_info.pNext = nullptr;
|
||||||
|
input_info.flags = 0;
|
||||||
|
input_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
input_info.primitiveRestartEnable = VK_FALSE;
|
||||||
|
pipeline_info.pInputAssemblyState = &input_info;
|
||||||
|
pipeline_info.pTessellationState = nullptr;
|
||||||
|
VkPipelineViewportStateCreateInfo viewport_state_info;
|
||||||
|
viewport_state_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewport_state_info.pNext = nullptr;
|
||||||
|
viewport_state_info.flags = 0;
|
||||||
|
viewport_state_info.viewportCount = 1;
|
||||||
|
viewport_state_info.pViewports = nullptr;
|
||||||
|
viewport_state_info.scissorCount = 1;
|
||||||
|
viewport_state_info.pScissors = nullptr;
|
||||||
|
pipeline_info.pViewportState = &viewport_state_info;
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterization_info;
|
||||||
|
rasterization_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterization_info.pNext = nullptr;
|
||||||
|
rasterization_info.flags = 0;
|
||||||
|
rasterization_info.depthClampEnable = VK_FALSE;
|
||||||
|
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rasterization_info.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
rasterization_info.depthBiasEnable = VK_FALSE;
|
||||||
|
rasterization_info.depthBiasConstantFactor = 0;
|
||||||
|
rasterization_info.depthBiasClamp = 0;
|
||||||
|
rasterization_info.depthBiasSlopeFactor = 0;
|
||||||
|
rasterization_info.lineWidth = 1.0f;
|
||||||
|
pipeline_info.pRasterizationState = &rasterization_info;
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisample_info;
|
||||||
|
multisample_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisample_info.pNext = nullptr;
|
||||||
|
multisample_info.flags = 0;
|
||||||
|
multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
multisample_info.sampleShadingEnable = VK_FALSE;
|
||||||
|
multisample_info.minSampleShading = 0;
|
||||||
|
multisample_info.pSampleMask = nullptr;
|
||||||
|
multisample_info.alphaToCoverageEnable = VK_FALSE;
|
||||||
|
multisample_info.alphaToOneEnable = VK_FALSE;
|
||||||
|
pipeline_info.pMultisampleState = &multisample_info;
|
||||||
|
pipeline_info.pDepthStencilState = nullptr;
|
||||||
|
VkPipelineColorBlendStateCreateInfo blend_info;
|
||||||
|
blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
blend_info.pNext = nullptr;
|
||||||
|
blend_info.flags = 0;
|
||||||
|
blend_info.logicOpEnable = VK_FALSE;
|
||||||
|
blend_info.logicOp = VK_LOGIC_OP_NO_OP;
|
||||||
|
VkPipelineColorBlendAttachmentState blend_attachments[1];
|
||||||
|
blend_attachments[0].blendEnable = VK_TRUE;
|
||||||
|
blend_attachments[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blend_attachments[0].dstColorBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blend_attachments[0].colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend_attachments[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blend_attachments[0].dstAlphaBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blend_attachments[0].alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend_attachments[0].colorWriteMask = 0xF;
|
||||||
|
blend_info.attachmentCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(blend_attachments));
|
||||||
|
blend_info.pAttachments = blend_attachments;
|
||||||
|
std::memset(blend_info.blendConstants, 0, sizeof(blend_info.blendConstants));
|
||||||
|
pipeline_info.pColorBlendState = &blend_info;
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamic_state_info;
|
||||||
|
dynamic_state_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamic_state_info.pNext = nullptr;
|
||||||
|
dynamic_state_info.flags = 0;
|
||||||
|
VkDynamicState dynamic_states[] = {
|
||||||
|
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
||||||
|
};
|
||||||
|
dynamic_state_info.dynamicStateCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(dynamic_states));
|
||||||
|
dynamic_state_info.pDynamicStates = dynamic_states;
|
||||||
|
pipeline_info.pDynamicState = &dynamic_state_info;
|
||||||
|
pipeline_info.layout = pipeline_layout_;
|
||||||
|
pipeline_info.renderPass = render_pass_;
|
||||||
|
pipeline_info.subpass = 0;
|
||||||
|
pipeline_info.basePipelineHandle = nullptr;
|
||||||
|
pipeline_info.basePipelineIndex = -1;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2016 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_UI_VULKAN_BLITTER_H_
|
||||||
|
#define XENIA_UI_VULKAN_BLITTER_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "xenia/ui/vulkan/vulkan.h"
|
||||||
|
#include "xenia/ui/vulkan/vulkan_device.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace ui {
|
||||||
|
namespace vulkan {
|
||||||
|
|
||||||
|
class Blitter {
|
||||||
|
public:
|
||||||
|
Blitter();
|
||||||
|
~Blitter();
|
||||||
|
|
||||||
|
bool Initialize(VulkanDevice* device);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
// Queues commands to blit a texture to another texture.
|
||||||
|
void BlitTexture2D(VkCommandBuffer command_buffer, VkImage src_image,
|
||||||
|
VkImageView src_image_view, VkOffset2D src_offset,
|
||||||
|
VkExtent2D src_extents, VkImage dst_image,
|
||||||
|
VkImageView dst_image_view, VkFilter filter,
|
||||||
|
bool swap_channels);
|
||||||
|
|
||||||
|
void CopyColorTexture2D(VkCommandBuffer command_buffer, VkImage src_image,
|
||||||
|
VkImageView src_image_view, VkOffset2D src_offset,
|
||||||
|
VkImage dst_image, VkImageView dst_image_view,
|
||||||
|
VkExtent2D extents, VkFilter filter,
|
||||||
|
bool swap_channels);
|
||||||
|
void CopyDepthTexture(VkCommandBuffer command_buffer, VkImage src_image,
|
||||||
|
VkImageView src_image_view, VkOffset2D src_offset,
|
||||||
|
VkImage dst_image, VkImageView dst_image_view,
|
||||||
|
VkExtent2D extents);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkRenderPass CreateRenderPass(VkFormat output_format);
|
||||||
|
VkPipeline CreatePipeline(VkRenderPass render_pass);
|
||||||
|
|
||||||
|
VulkanDevice* device_ = nullptr;
|
||||||
|
VkPipeline pipeline_color_ = nullptr;
|
||||||
|
VkPipeline pipeline_depth_ = nullptr;
|
||||||
|
VkPipelineLayout pipeline_layout_ = nullptr;
|
||||||
|
VkShaderModule blit_vertex_ = nullptr;
|
||||||
|
VkShaderModule blit_color_ = nullptr;
|
||||||
|
VkShaderModule blit_depth_ = nullptr;
|
||||||
|
VkDescriptorSetLayout descriptor_set_layout_ = nullptr;
|
||||||
|
VkRenderPass render_pass_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace vulkan
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_UI_VULKAN_BLITTER_H_
|
Loading…
Reference in New Issue