It builds! With some shortcuts, of course.

This commit is contained in:
Henrik Rydgård 2017-08-19 17:32:10 +02:00
parent 417b96a1b0
commit 0a0494ef8e
19 changed files with 1462 additions and 1464 deletions

View file

@ -167,120 +167,14 @@ void TransitionFromPresent(VkCommandBuffer cmd, VkImage image) {
VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
}
VkCommandBuffer VulkanContext::GetInitCommandBuffer() {
void VulkanContext::BeginFrame() {
FrameData *frame = &frame_[curFrame_];
if (!frame->hasInitCommands) {
VulkanBeginCommandBuffer(frame->cmdInit);
frame->hasInitCommands = true;
}
return frame_[curFrame_].cmdInit;
}
void VulkanContext::QueueBeforeSurfaceRender(VkCommandBuffer cmd) {
cmdQueue_.push_back(cmd);
}
VkCommandBuffer VulkanContext::BeginFrame() {
FrameData *frame = &frame_[curFrame_];
// Get the index of the next available swapchain image, and a semaphore to block command buffer execution on.
// Now, I wonder if we should do this early in the frame or late? Right now we do it early, which should be fine.
VkResult res = vkAcquireNextImageKHR(device_, swap_chain_, UINT64_MAX, acquireSemaphore_, VK_NULL_HANDLE, &current_buffer);
// TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
// return codes
assert(res == VK_SUCCESS);
// Make sure the very last command buffer from the frame before the previous has been fully executed.
WaitAndResetFence(frame->fence);
// Process pending deletes.
frame->deleteList.PerformDeletes(device_);
// Reset both command buffers in one fell swoop.
// Note that on the first frame, there might already be commands so don't reset in that case.
if (!frame->hasInitCommands) {
vkResetCommandPool(device_, frame->cmdPool, 0);
}
VkCommandBufferBeginInfo begin = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
begin.pInheritanceInfo = nullptr;
res = vkBeginCommandBuffer(frame->cmdBuf, &begin);
TransitionFromPresent(frame->cmdBuf, swapChainBuffers[current_buffer].image);
return frame->cmdBuf;
}
VkCommandBuffer VulkanContext::BeginSurfaceRenderPass(VkClearValue clear_values[2]) {
FrameData *frame = &frame_[curFrame_];
VkRenderPassBeginInfo rp_begin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
rp_begin.renderPass = surface_render_pass_;
rp_begin.framebuffer = framebuffers_[current_buffer];
rp_begin.renderArea.offset.x = 0;
rp_begin.renderArea.offset.y = 0;
rp_begin.renderArea.extent.width = width_;
rp_begin.renderArea.extent.height = height_;
rp_begin.clearValueCount = 2;
rp_begin.pClearValues = clear_values;
vkCmdBeginRenderPass(frame->cmdBuf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
return frame->cmdBuf;
}
void VulkanContext::EndSurfaceRenderPass() {
FrameData *frame = &frame_[curFrame_];
// ILOG("VulkanContext::EndSurfaceRenderPass");
vkCmdEndRenderPass(frame->cmdBuf);
}
void VulkanContext::EndFrame() {
FrameData *frame = &frame_[curFrame_];
TransitionToPresent(frame->cmdBuf, swapChainBuffers[current_buffer].image);
VkResult res = vkEndCommandBuffer(frame->cmdBuf);
assert(res == VK_SUCCESS);
// So the sequence will be, cmdInit, [cmdQueue_], frame->cmdBuf.
// This way we bunch up all the initialization needed for the frame, we render to
// other buffers before the back buffer, and then last we render to the backbuffer.
int numCmdBufs = 0;
std::vector<VkCommandBuffer> cmdBufs;
if (frame->hasInitCommands) {
vkEndCommandBuffer(frame->cmdInit);
cmdBufs.push_back(frame->cmdInit);
frame->hasInitCommands = false;
}
for (auto cmd : cmdQueue_) {
cmdBufs.push_back(cmd);
}
cmdQueue_.clear();
cmdBufs.push_back(frame->cmdBuf);
VkSubmitInfo submit_info = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &acquireSemaphore_;
VkPipelineStageFlags waitStage[1] = { VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
submit_info.pWaitDstStageMask = waitStage;
submit_info.commandBufferCount = (uint32_t)cmdBufs.size();
submit_info.pCommandBuffers = cmdBufs.data();
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &renderingCompleteSemaphore_;
res = vkQueueSubmit(gfx_queue_, 1, &submit_info, frame->fence);
assert(res == VK_SUCCESS);
VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
present.swapchainCount = 1;
present.pSwapchains = &swap_chain_;
present.pImageIndices = &current_buffer;
present.pWaitSemaphores = &renderingCompleteSemaphore_;
present.waitSemaphoreCount = 1;
present.pResults = NULL;
res = vkQueuePresentKHR(gfx_queue_, &present);
// TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
// return codes
assert(!res);
frame->deleteList.Take(globalDeleteList_);
frame_[curFrame_].deleteList.Take(globalDeleteList_);
curFrame_++;
if (curFrame_ >= inflightFrames_) {
curFrame_ = 0;
@ -308,72 +202,19 @@ bool VulkanContext::MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirem
return false;
}
void VulkanBeginCommandBuffer(VkCommandBuffer cmd) {
VkResult U_ASSERT_ONLY res;
VkCommandBufferBeginInfo cmd_buf_info = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
cmd_buf_info.pInheritanceInfo = nullptr;
cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
res = vkBeginCommandBuffer(cmd, &cmd_buf_info);
assert(res == VK_SUCCESS);
}
bool VulkanContext::InitObjects(bool depthPresent) {
int physical_device = 0; // TODO
bool VulkanContext::InitObjects() {
InitQueue();
// Create frame data
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
VkResult U_ASSERT_ONLY res;
VkCommandPoolCreateInfo cmd_pool_info = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
cmd_pool_info.queueFamilyIndex = graphics_queue_family_index_;
cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
res = vkCreateCommandPool(device_, &cmd_pool_info, NULL, &frame_[i].cmdPool);
assert(res == VK_SUCCESS);
VkCommandBufferAllocateInfo cmd_alloc = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
cmd_alloc.commandPool = frame_[i].cmdPool;
cmd_alloc.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmd_alloc.commandBufferCount = 2;
VkCommandBuffer cmdBuf[2];
res = vkAllocateCommandBuffers(device_, &cmd_alloc, cmdBuf);
assert(res == VK_SUCCESS);
frame_[i].cmdBuf = cmdBuf[0];
frame_[i].cmdInit = cmdBuf[1];
frame_[i].fence = CreateFence(true); // So it can be instantly waited on
}
VkCommandBuffer cmd = GetInitCommandBuffer();
if (!InitSwapchain(cmd)) {
if (!InitSwapchain()) {
return false;
}
InitDepthStencilBuffer(cmd);
InitSurfaceRenderPass(depthPresent, true);
InitFramebuffers(depthPresent);
// The init command buffer will be executed as part of the first frame.
return true;
}
void VulkanContext::DestroyObjects() {
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
VkCommandBuffer cmdBuf[2];
cmdBuf[0] = frame_[i].cmdBuf;
cmdBuf[1] = frame_[i].cmdInit;
vkFreeCommandBuffers(device_, frame_[i].cmdPool, 2, cmdBuf);
vkDestroyCommandPool(device_, frame_[i].cmdPool, nullptr);
}
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
vkDestroyFence(device_, frame_[i].fence, nullptr);
}
DestroyFramebuffers();
DestroySurfaceRenderPass();
DestroyDepthStencilBuffer();
DestroySwapChain();
if (swapchain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(device_, swapchain_, nullptr);
swapchain_ = VK_NULL_HANDLE;
// If there happen to be any pending deletes, now is a good time.
for (int i = 0; i < ARRAY_SIZE(frame_); i++) {
@ -670,78 +511,6 @@ void VulkanContext::DestroyDebugMsgCallback() {
}
}
void VulkanContext::InitDepthStencilBuffer(VkCommandBuffer cmd) {
VkResult U_ASSERT_ONLY res;
bool U_ASSERT_ONLY pass;
const VkFormat depth_format = deviceInfo_.preferredDepthStencilFormat;
int aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
VkImageCreateInfo image_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
image_info.imageType = VK_IMAGE_TYPE_2D;
image_info.format = depth_format;
image_info.extent.width = width_;
image_info.extent.height = height_;
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
image_info.queueFamilyIndexCount = 0;
image_info.pQueueFamilyIndices = NULL;
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
image_info.flags = 0;
VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
mem_alloc.allocationSize = 0;
mem_alloc.memoryTypeIndex = 0;
VkMemoryRequirements mem_reqs;
depth.format = depth_format;
res = vkCreateImage(device_, &image_info, NULL, &depth.image);
assert(res == VK_SUCCESS);
vkGetImageMemoryRequirements(device_, depth.image, &mem_reqs);
mem_alloc.allocationSize = mem_reqs.size;
/* Use the memory properties to determine the type of memory required */
pass = MemoryTypeFromProperties(mem_reqs.memoryTypeBits,
0, /* No requirements */
&mem_alloc.memoryTypeIndex);
assert(pass);
res = vkAllocateMemory(device_, &mem_alloc, NULL, &depth.mem);
assert(res == VK_SUCCESS);
res = vkBindImageMemory(device_, depth.image, depth.mem, 0);
assert(res == VK_SUCCESS);
TransitionImageLayout2(cmd, depth.image,
aspectMask,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT);
VkImageViewCreateInfo depth_view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
depth_view_info.image = depth.image;
depth_view_info.format = depth_format;
depth_view_info.components.r = VK_COMPONENT_SWIZZLE_R;
depth_view_info.components.g = VK_COMPONENT_SWIZZLE_G;
depth_view_info.components.b = VK_COMPONENT_SWIZZLE_B;
depth_view_info.components.a = VK_COMPONENT_SWIZZLE_A;
depth_view_info.subresourceRange.aspectMask = aspectMask;
depth_view_info.subresourceRange.baseMipLevel = 0;
depth_view_info.subresourceRange.levelCount = 1;
depth_view_info.subresourceRange.baseArrayLayer = 0;
depth_view_info.subresourceRange.layerCount = 1;
depth_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
depth_view_info.flags = 0;
res = vkCreateImageView(device_, &depth_view_info, NULL, &depth.view);
assert(res == VK_SUCCESS);
}
#ifdef _WIN32
void VulkanContext::InitSurfaceWin32(HINSTANCE conn, HWND wnd) {
connection = conn;
@ -855,39 +624,32 @@ void VulkanContext::InitQueue() {
// supported format will be returned.
if (formatCount == 0 || (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)) {
ILOG("swapchain_format: Falling back to B8G8R8A8_UNORM");
swapchain_format = VK_FORMAT_B8G8R8A8_UNORM;
swapchainFormat_ = VK_FORMAT_B8G8R8A8_UNORM;
} else {
swapchain_format = VK_FORMAT_UNDEFINED;
swapchainFormat_ = VK_FORMAT_UNDEFINED;
for (uint32_t i = 0; i < formatCount; ++i) {
if (surfFormats[i].colorSpace != VK_COLORSPACE_SRGB_NONLINEAR_KHR) {
continue;
}
if (surfFormats[i].format == VK_FORMAT_B8G8R8A8_UNORM || surfFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) {
swapchain_format = surfFormats[i].format;
swapchainFormat_ = surfFormats[i].format;
break;
}
}
if (swapchain_format == VK_FORMAT_UNDEFINED) {
if (swapchainFormat_ == VK_FORMAT_UNDEFINED) {
// Okay, take the first one then.
swapchain_format = surfFormats[0].format;
swapchainFormat_ = surfFormats[0].format;
}
ILOG("swapchain_format: %d (/%d)", swapchain_format, formatCount);
ILOG("swapchain_format: %d (/%d)", swapchainFormat_, formatCount);
}
delete[] surfFormats;
vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_);
ILOG("gfx_queue_: %p", gfx_queue_);
VkSemaphoreCreateInfo semaphoreCreateInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
semaphoreCreateInfo.flags = 0;
res = vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &acquireSemaphore_);
assert(res == VK_SUCCESS);
res = vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &renderingCompleteSemaphore_);
assert(res == VK_SUCCESS);
}
bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
bool VulkanContext::InitSwapchain() {
VkResult U_ASSERT_ONLY res;
VkSurfaceCapabilitiesKHR surfCapabilities;
@ -967,7 +729,7 @@ bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
VkSwapchainCreateInfoKHR swap_chain_info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
swap_chain_info.surface = surface_;
swap_chain_info.minImageCount = desiredNumberOfSwapChainImages;
swap_chain_info.imageFormat = swapchain_format;
swap_chain_info.imageFormat = swapchainFormat_;
swap_chain_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
swap_chain_info.imageExtent.width = swapChainExtent.width;
swap_chain_info.imageExtent.height = swapChainExtent.height;
@ -988,141 +750,15 @@ bool VulkanContext::InitSwapchain(VkCommandBuffer cmd) {
swap_chain_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
}
res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swap_chain_);
res = vkCreateSwapchainKHR(device_, &swap_chain_info, NULL, &swapchain_);
assert(res == VK_SUCCESS);
if (res != VK_SUCCESS) {
return false;
}
res = vkGetSwapchainImagesKHR(device_, swap_chain_, &swapchainImageCount, nullptr);
assert(res == VK_SUCCESS);
ILOG("Vulkan swapchain image count: %d", swapchainImageCount);
VkImage* swapchainImages = new VkImage[swapchainImageCount];
assert(swapchainImages);
res = vkGetSwapchainImagesKHR(device_, swap_chain_, &swapchainImageCount, swapchainImages);
assert(res == VK_SUCCESS);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
swap_chain_buffer sc_buffer;
VkImageViewCreateInfo color_image_view = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
color_image_view.format = swapchain_format;
color_image_view.components.r = VK_COMPONENT_SWIZZLE_R;
color_image_view.components.g = VK_COMPONENT_SWIZZLE_G;
color_image_view.components.b = VK_COMPONENT_SWIZZLE_B;
color_image_view.components.a = VK_COMPONENT_SWIZZLE_A;
color_image_view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
color_image_view.subresourceRange.baseMipLevel = 0;
color_image_view.subresourceRange.levelCount = 1;
color_image_view.subresourceRange.baseArrayLayer = 0;
color_image_view.subresourceRange.layerCount = 1;
color_image_view.viewType = VK_IMAGE_VIEW_TYPE_2D;
color_image_view.flags = 0;
sc_buffer.image = swapchainImages[i];
// TODO: Pre-set them to PRESENT_SRC_KHR, as the first thing we do after acquiring
// in image to render to will be to transition them away from that.
TransitionImageLayout2(cmd, sc_buffer.image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
color_image_view.image = sc_buffer.image;
res = vkCreateImageView(device_, &color_image_view, NULL, &sc_buffer.view);
swapChainBuffers.push_back(sc_buffer);
assert(res == VK_SUCCESS);
}
delete[] swapchainImages;
current_buffer = 0;
return true;
}
void VulkanContext::InitSurfaceRenderPass(bool include_depth, bool clear) {
// Need attachments for render target and depth buffer
VkAttachmentDescription attachments[2]{};
attachments[0].format = swapchain_format;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments[0].flags = 0;
if (include_depth) {
attachments[1].format = depth.format;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].stencilLoadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments[1].flags = 0;
}
VkAttachmentReference color_reference{};
color_reference.attachment = 0;
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference depth_reference{};
depth_reference.attachment = 1;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.flags = 0;
subpass.inputAttachmentCount = 0;
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &color_reference;
subpass.pResolveAttachments = nullptr;
subpass.pDepthStencilAttachment = include_depth ? &depth_reference : nullptr;
subpass.preserveAttachmentCount = 0;
subpass.pPreserveAttachments = nullptr;
VkRenderPassCreateInfo rp_info{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
rp_info.attachmentCount = include_depth ? 2 : 1;
rp_info.pAttachments = attachments;
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.dependencyCount = 0;
rp_info.pDependencies = nullptr;
VkResult U_ASSERT_ONLY res = vkCreateRenderPass(device_, &rp_info, nullptr, &surface_render_pass_);
assert(res == VK_SUCCESS);
}
void VulkanContext::InitFramebuffers(bool include_depth) {
VkResult U_ASSERT_ONLY res;
VkImageView attachments[2];
attachments[1] = depth.view;
ILOG("InitFramebuffers: %dx%d", width_, height_);
VkFramebufferCreateInfo fb_info{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
fb_info.renderPass = surface_render_pass_;
fb_info.attachmentCount = include_depth ? 2 : 1;
fb_info.pAttachments = attachments;
fb_info.width = width_;
fb_info.height = height_;
fb_info.layers = 1;
framebuffers_.resize(swapchainImageCount);
for (uint32_t i = 0; i < swapchainImageCount; i++) {
attachments[0] = swapChainBuffers[i].view;
res = vkCreateFramebuffer(device_, &fb_info, nullptr, &framebuffers_[i]);
assert(res == VK_SUCCESS);
}
}
VkFence VulkanContext::CreateFence(bool presignalled) {
VkFence fence;
VkFenceCreateInfo fenceInfo{ VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
@ -1131,49 +767,6 @@ VkFence VulkanContext::CreateFence(bool presignalled) {
return fence;
}
void VulkanContext::WaitAndResetFence(VkFence fence) {
vkWaitForFences(device_, 1, &fence, true, UINT64_MAX);
vkResetFences(device_, 1, &fence);
}
void VulkanContext::DestroyDepthStencilBuffer() {
if (depth.view != VK_NULL_HANDLE)
vkDestroyImageView(device_, depth.view, nullptr);
if (depth.image != VK_NULL_HANDLE)
vkDestroyImage(device_, depth.image, nullptr);
if (depth.mem != VK_NULL_HANDLE)
vkFreeMemory(device_, depth.mem, nullptr);
depth.view = VK_NULL_HANDLE;
depth.image = VK_NULL_HANDLE;
depth.mem = VK_NULL_HANDLE;
}
void VulkanContext::DestroySwapChain() {
for (uint32_t i = 0; i < swapchainImageCount; i++) {
vkDestroyImageView(device_, swapChainBuffers[i].view, nullptr);
}
if (swap_chain_ != VK_NULL_HANDLE)
vkDestroySwapchainKHR(device_, swap_chain_, nullptr);
swap_chain_ = VK_NULL_HANDLE;
swapChainBuffers.clear();
vkDestroySemaphore(device_, acquireSemaphore_, nullptr);
vkDestroySemaphore(device_, renderingCompleteSemaphore_, nullptr);
}
void VulkanContext::DestroyFramebuffers() {
for (uint32_t i = 0; i < framebuffers_.size(); i++) {
vkDestroyFramebuffer(device_, framebuffers_[i], nullptr);
}
framebuffers_.clear();
}
void VulkanContext::DestroySurfaceRenderPass() {
if (surface_render_pass_ != VK_NULL_HANDLE)
vkDestroyRenderPass(device_, surface_render_pass_, nullptr);
surface_render_pass_ = VK_NULL_HANDLE;
}
void VulkanContext::DestroyDevice() {
vkDestroyDevice(device_, nullptr);
device_ = nullptr;

View file

@ -195,8 +195,7 @@ private:
std::vector<Callback> callbacks_;
};
// VulkanContext sets up the basics necessary for rendering to a window, including framebuffers etc.
// Optionally, it can create a depth buffer for you as well.
// VulkanContext manages the device and swapchain, and deferred deletion of objects.
class VulkanContext {
public:
VulkanContext();
@ -227,19 +226,12 @@ public:
void ReinitSurfaceAndroid(int width, int height);
#endif
void InitQueue();
bool InitObjects(bool depthPresent);
bool InitSwapchain(VkCommandBuffer cmd);
void InitSurfaceRenderPass(bool include_depth, bool clear);
void InitFramebuffers(bool include_depth);
void InitDepthStencilBuffer(VkCommandBuffer cmd);
bool InitObjects();
bool InitSwapchain();
// Also destroys the surface.
void DestroyObjects();
void DestroySurfaceRenderPass();
void DestroyFramebuffers();
void DestroySwapChain();
void DestroyDepthStencilBuffer();
void DestroyDevice();
void WaitUntilQueueIdle();
@ -248,41 +240,17 @@ public:
VkFence CreateFence(bool presignalled);
bool CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule);
void WaitAndResetFence(VkFence fence);
int GetBackbufferWidth() { return width_; }
int GetBackbufferHeight() { return height_; }
int GetWidth() { return width_; }
int GetHeight() { return height_; }
VkCommandBuffer GetInitCommandBuffer();
VkFramebuffer GetSurfaceFramebuffer() {
return framebuffers_[current_buffer];
}
// This must only be accessed between BeginSurfaceRenderPass and EndSurfaceRenderPass.
VkCommandBuffer GetSurfaceCommandBuffer() {
return frame_[curFrame_].cmdBuf;
}
VkCommandBuffer BeginFrame();
// The surface render pass is special because it has to acquire the backbuffer, and may thus "block".
// Use the returned command buffer to enqueue commands that render to the backbuffer.
// To render to other buffers first, you can submit additional commandbuffers using QueueBeforeSurfaceRender(cmd).
VkCommandBuffer BeginSurfaceRenderPass(VkClearValue clear_values[2]);
// May eventually need the ability to break and resume the backbuffer render pass in a few rare cases.
void EndSurfaceRenderPass();
void BeginFrame();
void EndFrame();
void QueueBeforeSurfaceRender(VkCommandBuffer cmd);
bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr);
void DestroyDebugMsgCallback();
VkRenderPass GetSurfaceRenderPass() const {
return surface_render_pass_;
}
VkPhysicalDevice GetPhysicalDevice(int n = 0) const {
return physical_devices_[n];
}
@ -327,8 +295,19 @@ public:
return inflightFrames_;
}
int GetCurFrame() const {
return curFrame_;
}
VkSwapchainKHR GetSwapchain() const {
return swapchain_;
}
VkFormat GetSwapchainFormat() const {
return swapchainFormat_;
}
enum {
MAX_INFLIGHT_FRAMES = 2,
MAX_INFLIGHT_FRAMES = 3,
};
private:
@ -340,9 +319,6 @@ private:
bool CheckLayers(const std::vector<LayerProperties> &layer_props, const std::vector<const char *> &layer_names) const;
VkSemaphore acquireSemaphore_;
VkSemaphore renderingCompleteSemaphore_;
#ifdef _WIN32
HINSTANCE connection = nullptr; // hInstance - Windows Instance
HWND window = nullptr; // hWnd - window handle
@ -380,36 +356,15 @@ private:
// Custom collection of things that are good to know
VulkanPhysicalDeviceInfo deviceInfo_;
struct swap_chain_buffer {
VkImage image;
VkImageView view;
};
// Swap chain
int width_ = 0;
int height_ = 0;
int flags_ = 0;
VkFormat swapchain_format = VK_FORMAT_UNDEFINED;
std::vector<VkFramebuffer> framebuffers_;
uint32_t swapchainImageCount = 0;
VkSwapchainKHR swap_chain_ = VK_NULL_HANDLE;
std::vector<swap_chain_buffer> swapChainBuffers;
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
// Manages flipping command buffers for the backbuffer render pass.
// It is recommended to do the same for other rendering passes.
struct FrameData {
FrameData() : hasInitCommands(false), cmdInit(nullptr), cmdBuf(nullptr) {}
VkFence fence;
bool hasInitCommands;
// TODO: Move to frame data
VkCommandPool cmdPool;
VkCommandBuffer cmdInit;
VkCommandBuffer cmdBuf;
FrameData() {}
VulkanDeleteList deleteList;
};
FrameData frame_[MAX_INFLIGHT_FRAMES];
@ -421,15 +376,9 @@ private:
std::vector<VkDebugReportCallbackEXT> msg_callbacks;
struct {
VkFormat format;
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory mem = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
} depth;
VkSwapchainKHR swapchain_;
VkFormat swapchainFormat_;
VkRenderPass surface_render_pass_ = VK_NULL_HANDLE;
uint32_t current_buffer = 0;
uint32_t queue_count = 0;
VkPhysicalDeviceFeatures featuresAvailable_;
@ -438,15 +387,15 @@ private:
std::vector<VkCommandBuffer> cmdQueue_;
};
// Stand-alone utility functions
void VulkanBeginCommandBuffer(VkCommandBuffer cmd);
// Detailed control.
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask);
void TransitionFromPresent(VkCommandBuffer cmd, VkImage image);
void TransitionToPresent(VkCommandBuffer cmd, VkImage image);
// GLSL compiler
void init_glslang();
void finalize_glslang();

View file

@ -84,11 +84,9 @@ uint8_t *VulkanTexture::Lock(int level, int *rowPitch) {
return (uint8_t *)data;
}
void VulkanTexture::Unlock() {
void VulkanTexture::Unlock(VkCommandBuffer cmd) {
vkUnmapMemory(vulkan_->GetDevice(), mappableMemory);
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
// if we already have an image, queue it for destruction and forget it.
Wipe();
@ -227,11 +225,9 @@ static bool IsDepthStencilFormat(VkFormat format) {
}
}
bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) {
Wipe();
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
tex_width = w;
tex_height = h;
numMips_ = numMips;
@ -336,7 +332,7 @@ bool VulkanTexture::CreateDirect(int w, int h, int numMips, VkFormat format, VkI
return true;
}
void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
void VulkanTexture::UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength) {
VkBufferImageCopy copy_region = {};
copy_region.bufferOffset = offset;
copy_region.bufferRowLength = (uint32_t)rowLength;
@ -349,12 +345,10 @@ void VulkanTexture::UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buf
copy_region.imageSubresource.baseArrayLayer = 0;
copy_region.imageSubresource.layerCount = 1;
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
vkCmdCopyBufferToImage(cmd, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
}
void VulkanTexture::EndCreate() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
void VulkanTexture::EndCreate(VkCommandBuffer cmd) {
TransitionImageLayout2(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
@ -362,8 +356,7 @@ void VulkanTexture::EndCreate() {
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
}
void VulkanTexture::TransitionForUpload() {
VkCommandBuffer cmd = vulkan_->GetInitCommandBuffer();
void VulkanTexture::TransitionForUpload(VkCommandBuffer cmd) {
TransitionImageLayout2(cmd, image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,

View file

@ -26,16 +26,16 @@ public:
// been called.
VkResult Create(int w, int h, VkFormat format);
uint8_t *Lock(int level, int *rowPitch);
void Unlock();
void Unlock(VkCommandBuffer cmd);
// Fast uploads from buffer. Mipmaps supported.
// Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip.
// When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.
bool CreateDirect(int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
void UploadMip(int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate();
bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr);
void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels
void EndCreate(VkCommandBuffer cmd);
void TransitionForUpload();
void TransitionForUpload(VkCommandBuffer cmd);
int GetNumMips() const { return numMips_; }
void Destroy();

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,8 @@
#include <cstdint>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Common/Vulkan/VulkanContext.h"
#include "math/dataconv.h"
@ -13,14 +15,14 @@
// The cool thing is that you can Flush on a different thread than you record the commands on!
enum VkRenderCmd : uint8_t {
VKR_STENCIL,
VKR_BLEND,
VKR_VIEWPORT,
VKR_SCISSOR,
VKR_CLEAR,
VKR_DRAW,
VKR_DRAW_INDEXED,
enum class VkRenderCmd : uint8_t {
STENCIL,
BLEND,
VIEWPORT,
SCISSOR,
CLEAR,
DRAW,
DRAW_INDEXED,
};
struct VkRenderData {
@ -80,47 +82,160 @@ struct VkRenderData {
};
};
struct VKRRenderPass {
VkFramebuffer framebuffer;
uint32_t clearColor;
float clearZ;
int clearStencil;
int clearMask = 0; // VK_IMAGE_ASPECT_COLOR_BIT etc
int dontCareMask = 0;
int numDraws;
enum class VKStepType : uint8_t {
RENDER,
COPY,
BLIT,
READBACK,
};
class VKRFramebuffer;
enum class RenderPassAction {
DONT_CARE,
CLEAR,
KEEP,
};
struct VKRStep {
VKRStep(VKStepType _type) : stepType(_type) {}
VKStepType stepType;
std::vector<VkRenderData> commands;
union {
struct {
VKRFramebuffer *framebuffer;
RenderPassAction color;
RenderPassAction depthStencil;
uint32_t clearColor;
float clearDepth;
int clearStencil;
int numDraws;
VkImageLayout finalColorLayout;
} render;
struct {
VKRFramebuffer *src;
VKRFramebuffer *dst;
VkRect2D srcRect;
VkOffset2D dstPos;
int aspectMask;
} copy;
struct {
VKRFramebuffer *src;
VKRFramebuffer *dst;
VkRect2D srcRect;
VkRect2D dstRect;
int aspectMask;
VkFilter filter;
} blit;
struct {
VKRFramebuffer *src;
void *destPtr;
VkRect2D srcRect;
} readback;
};
};
// Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine
// to let them have individual non-pooled allocations. Until it's not fine. We'll see.
struct VKImage {
VkImage image;
VkImageView imageView;
VkDeviceMemory memory;
VkImageLayout layout;
};
void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color);
class VKRFramebuffer {
public:
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height) : vulkan_(vk) {
width = _width;
height = _height;
CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true);
CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false);
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
VkImageView views[2]{};
fbci.renderPass = renderPass;
fbci.attachmentCount = 2;
fbci.pAttachments = views;
views[0] = color.imageView;
views[1] = depth.imageView;
fbci.width = width;
fbci.height = height;
fbci.layers = 1;
vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf);
}
~VKRFramebuffer() {
vulkan_->Delete().QueueDeleteImage(color.image);
vulkan_->Delete().QueueDeleteImage(depth.image);
vulkan_->Delete().QueueDeleteImageView(color.imageView);
vulkan_->Delete().QueueDeleteImageView(depth.imageView);
vulkan_->Delete().QueueDeleteDeviceMemory(color.memory);
vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory);
vulkan_->Delete().QueueDeleteFramebuffer(framebuf);
}
int numShadows = 1; // TODO: Support this.
VkFramebuffer framebuf = VK_NULL_HANDLE;
VKImage color{};
VKImage depth{};
int width = 0;
int height = 0;
private:
VulkanContext *vulkan_;
};
class VulkanRenderManager {
public:
VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan) {}
VulkanRenderManager(VulkanContext *vulkan);
~VulkanRenderManager();
void ThreadFunc();
// Makes sure that the GPU has caught up enough that we can start writing buffers of this frame again.
void BeginFrameWrites();
void EndFrame();
void BindFramebufferAsRenderTarget(VKRFramebuffer *fb);
VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment);
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPoint);
void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkFilter filter);
void BeginRenderPass();
void SetViewport(const VkViewport &vp) {
VkRenderData data{ VKR_VIEWPORT };
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
VkRenderData data{ VkRenderCmd::VIEWPORT };
data.viewport.vp = vp;
curRp_->commands.push_back(data);
curStep_->commands.push_back(data);
}
void SetScissor(const VkRect2D &rc) {
VkRenderData data{ VKR_SCISSOR };
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
VkRenderData data{ VkRenderCmd::SCISSOR };
data.scissor.scissor = rc;
curRp_->commands.push_back(data);
curStep_->commands.push_back(data);
}
void SetBlendFactor(float color[4]) {
VkRenderData data{ VKR_BLEND };
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
VkRenderData data{ VkRenderCmd::BLEND };
CopyFloat4(data.blendColor.color, color);
curRp_->commands.push_back(data);
curStep_->commands.push_back(data);
}
void Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask);
void Draw(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count) {
VkRenderData data{ VKR_DRAW };
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
VkRenderData data{ VkRenderCmd::DRAW };
data.draw.count = count;
data.draw.pipeline = pipeline;
data.draw.pipelineLayout = layout;
@ -130,12 +245,13 @@ public:
data.draw.numUboOffsets = numUboOffsets;
for (int i = 0; i < numUboOffsets; i++)
data.draw.uboOffsets[i] = uboOffsets[i];
curRp_->commands.push_back(data);
curRp_->numDraws++;
curStep_->commands.push_back(data);
curStep_->render.numDraws++;
}
void DrawIndexed(VkPipeline pipeline, VkPipelineLayout layout, VkDescriptorSet descSet, int numUboOffsets, uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, VkIndexType indexType) {
VkRenderData data{ VKR_DRAW };
_dbg_assert_(G3D, curStep_ && curStep_->stepType == VKStepType::RENDER);
VkRenderData data{ VkRenderCmd::DRAW_INDEXED };
data.drawIndexed.count = count;
data.drawIndexed.pipeline = pipeline;
data.drawIndexed.pipelineLayout = layout;
@ -148,21 +264,103 @@ public:
for (int i = 0; i < numUboOffsets; i++)
data.drawIndexed.uboOffsets[i] = uboOffsets[i];
data.drawIndexed.indexType = indexType;
curRp_->commands.push_back(data);
curRp_->numDraws++;
curStep_->commands.push_back(data);
curStep_->render.numDraws++;
}
// Can run on a different thread! Just make sure to use BeginFrameWrites.
void Flush(VkCommandBuffer cmd);
void Flush();
// Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot).
void Sync(VkCommandBuffer cmd);
void Sync();
std::vector<VKRRenderPass *> renderPasses_;
VKRRenderPass *curRp_;
std::vector<VKRStep *> steps_;
std::vector<VKRStep *> stepsOnThread_;
std::mutex rpLock_;
VKRStep *curStep_;
VkCommandBuffer GetInitCmd();
VkCommandBuffer GetSurfaceCommandBuffer() {
return frameData_[vulkan_->GetCurFrame()].mainCmd;
}
VkRenderPass GetSurfaceRenderPass() const {
return backbufferRenderPass_;
}
VkRenderPass GetRenderPass(int i) const {
return renderPasses_[i];
}
private:
void InitFramebuffers();
void InitSurfaceRenderPass();
void InitRenderpasses();
void InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
// The surface render pass is special because it has to acquire the backbuffer, and may thus "block".
// Use the returned command buffer to enqueue commands that render to the backbuffer.
// To render to other buffers first, you can submit additional commandbuffers using QueueBeforeSurfaceRender(cmd).
void BeginSurfaceRenderPass(VkCommandBuffer cmd, VkClearValue clear_value);
// May eventually need the ability to break and resume the backbuffer render pass in a few rare cases.
void EndSurfaceRenderPass(VkCommandBuffer cmd);
void EndCurrentRenderpass(VkCommandBuffer cmd);
void PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd);
void PerformCopy(const VKRStep &pass, VkCommandBuffer cmd);
void PerformBlit(const VKRStep &pass, VkCommandBuffer cmd);
inline int RPIndex(RenderPassAction color, RenderPassAction depth) {
return (int)depth * 3 + (int)color;
}
static void SetupTransitionToTransferSrc(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
static void SetupTransitionToTransferDst(VKImage &img, VkImageMemoryBarrier &barrier, VkImageAspectFlags aspect);
VkSemaphore acquireSemaphore_;
VkSemaphore renderingCompleteSemaphore;
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
// TODO: Create these on demand.
VkRenderPass renderPasses_[9];
struct FrameData {
VkFence fence;
VkCommandPool cmdPool;
VkCommandBuffer initCmd;
VkCommandBuffer mainCmd;
bool hasInitCommands;
};
FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
VulkanContext *vulkan_;
int curWidth_;
int curHeight_;
};
std::thread submissionThread;
std::mutex mutex_;
std::condition_variable condVar_;
struct SwapchainImageData {
VkImage image;
VkImageView view;
};
std::vector<VkFramebuffer> framebuffers_;
std::vector<SwapchainImageData> swapchainImages_;
uint32_t swapchainImageCount;
uint32_t current_buffer = 0;
VkRenderPass backbufferRenderPass_ = VK_NULL_HANDLE;
struct DepthBufferInfo {
VkFormat format;
VkImage image = VK_NULL_HANDLE;
VkDeviceMemory mem = VK_NULL_HANDLE;
VkImageView view = VK_NULL_HANDLE;
};
DepthBufferInfo depth_;
// Interpreter state
VkFramebuffer curFramebuffer_;
VkRenderPass curRenderPass_;
};

View file

@ -94,7 +94,7 @@ DrawEngineVulkan::DrawEngineVulkan(VulkanContext *vulkan, Draw::DrawContext *dra
InitDeviceObjects();
tessDataTransfer = new TessellationDataTransferVulkan(vulkan);
tessDataTransfer = new TessellationDataTransferVulkan(vulkan, draw);
}
void DrawEngineVulkan::InitDeviceObjects() {
@ -294,10 +294,11 @@ void DrawEngineVulkan::BeginFrame() {
// TODO : Find a better place to do this.
if (!nullTexture_) {
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
nullTexture_ = new VulkanTexture(vulkan_);
int w = 8;
int h = 8;
nullTexture_->CreateDirect(w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
nullTexture_->CreateDirect(cmdInit, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
uint32_t bindOffset;
VkBuffer bindBuf;
@ -308,8 +309,8 @@ void DrawEngineVulkan::BeginFrame() {
data[y*w + x] = 0; // black
}
}
nullTexture_->UploadMip(0, w, h, bindBuf, bindOffset, w);
nullTexture_->EndCreate();
nullTexture_->UploadMip(cmdInit, 0, w, h, bindBuf, bindOffset, w);
nullTexture_->EndCreate(cmdInit);
}
DirtyAllUBOs();
@ -643,13 +644,15 @@ void DrawEngineVulkan::DoFlush() {
// TODO: Should be enough to update this once per frame?
gpuStats.numTrackedVertexArrays = (int)vai_.size();
/*
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
if (cmd != lastCmd_) {
lastPipeline_ = nullptr;
lastCmd_ = cmd;
// Since we have a new cmdbuf, dirty our dynamic state so it gets re-set.
gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE|DIRTY_DEPTHSTENCIL_STATE|DIRTY_BLEND_STATE);
}
}*/
VkCommandBuffer cmd = VK_NULL_HANDLE;
VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::CURRENT_RENDERPASS);
if (!rp)
@ -1087,11 +1090,12 @@ void DrawEngineVulkan::UpdateUBOs(FrameData *frame) {
void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) {
int rowPitch;
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
if (prevSize < size) {
prevSize = size;
data_tex[0]->CreateDirect(size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[0]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
pos = (float *)data_tex[0]->Lock(0, &rowPitch);
@ -1100,7 +1104,7 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
if (prevSizeTex < size) {
prevSizeTex = size;
data_tex[1]->CreateDirect(size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[1]->CreateDirect(cmd, size, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
tex = (float *)data_tex[1]->Lock(0, &rowPitch);
}
@ -1110,19 +1114,20 @@ void DrawEngineVulkan::TessellationDataTransferVulkan::PrepareBuffers(float *&po
if (prevSizeCol < sizeColor) {
prevSizeCol = sizeColor;
data_tex[2]->CreateDirect(sizeColor, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
data_tex[2]->CreateDirect(cmd, sizeColor, 1, 1, VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
col = (float *)data_tex[2]->Lock(0, &rowPitch);
}
void DrawEngineVulkan::TessellationDataTransferVulkan::SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) {
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// Position
data_tex[0]->Unlock();
data_tex[0]->Unlock(cmd);
// Texcoords
if (hasTexCoords)
data_tex[1]->Unlock();
data_tex[1]->Unlock(cmd);
// Color
data_tex[2]->Unlock();
data_tex[2]->Unlock(cmd);
}

View file

@ -255,14 +255,15 @@ private:
// Hardware tessellation
class TessellationDataTransferVulkan : public TessellationDataTransfer {
private:
VulkanContext *vulkan;
VulkanContext *vulkan_;
Draw::DrawContext *draw_;
VulkanTexture *data_tex[3];
VkSampler sampler;
public:
TessellationDataTransferVulkan(VulkanContext *vulkan)
: TessellationDataTransfer(), vulkan(vulkan), data_tex(), sampler() {
TessellationDataTransferVulkan(VulkanContext *vulkan, Draw::DrawContext *draw)
: TessellationDataTransfer(), vulkan_(vulkan), draw_(draw), data_tex(), sampler() {
for (int i = 0; i < 3; i++)
data_tex[i] = new VulkanTexture(vulkan);
data_tex[i] = new VulkanTexture(vulkan_);
CreateSampler();
}
@ -270,7 +271,7 @@ private:
for (int i = 0; i < 3; i++)
delete data_tex[i];
vulkan->Delete().QueueDeleteSampler(sampler);
vulkan_->Delete().QueueDeleteSampler(sampler);
}
void SendDataToShader(const float *pos, const float *tex, const float *col, int size, bool hasColor, bool hasTexCoords) override;
void PrepareBuffers(float *&pos, float *&tex, float *&col, int size, bool hasColor, bool hasTexCoords) override;
@ -301,7 +302,7 @@ private:
samp.minLod = 0.0f;
samp.mipLodBias = 0.0f;
VkResult res = vkCreateSampler(vulkan->GetDevice(), &samp, nullptr, &sampler);
VkResult res = vkCreateSampler(vulkan_->GetDevice(), &samp, nullptr, &sampler);
assert(res == VK_SUCCESS);
}
};

View file

@ -28,6 +28,7 @@
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanMemory.h"
#include "Common/Vulkan/VulkanImage.h"
#include "Common/Vulkan/VulkanRenderManager.h"
#include "Common/ColorConv.h"
#include "Core/Host.h"
#include "Core/MemMap.h"
@ -131,7 +132,7 @@ void FramebufferManagerVulkan::InitDeviceObjects() {
assert(vsBasicTex_ != VK_NULL_HANDLE);
// Prime the 2D pipeline cache.
vulkan2D_.GetPipeline(pipelineCache2D_, vulkan_->GetSurfaceRenderPass(), vsBasicTex_, fsBasicTex_);
vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_RENDERPASS), vsBasicTex_, fsBasicTex_);
vulkan2D_.GetPipeline(pipelineCache2D_, (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::COMPATIBLE_RENDERPASS), vsBasicTex_, fsBasicTex_);
VkSamplerCreateInfo samp = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
@ -234,13 +235,15 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
drawPixelsTex_ = nullptr;
}
VkCommandBuffer initCmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
if (!drawPixelsTex_) {
drawPixelsTex_ = new VulkanTexture(vulkan_);
drawPixelsTex_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
drawPixelsTex_->CreateDirect(initCmd, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
// Initialize backbuffer texture for DrawPixels
drawPixelsTexFormat_ = srcPixelFormat;
} else {
drawPixelsTex_->TransitionForUpload();
drawPixelsTex_->TransitionForUpload(initCmd);
}
// TODO: We can just change the texture format and flip some bits around instead of this.
@ -297,25 +300,22 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor
VkBuffer buffer;
size_t offset = frameData_[curFrame_].push_->Push(data, width * height * 4, &buffer);
drawPixelsTex_->UploadMip(0, width, height, buffer, (uint32_t)offset, width);
drawPixelsTex_->EndCreate();
drawPixelsTex_->UploadMip(initCmd, 0, width, height, buffer, (uint32_t)offset, width);
drawPixelsTex_->EndCreate(initCmd);
overrideImageView_ = drawPixelsTex_->GetImageView();
}
void FramebufferManagerVulkan::SetViewport2D(int x, int y, int w, int h) {
VkViewport vp;
vp.minDepth = 0.0;
vp.maxDepth = 1.0;
vp.x = (float)x;
vp.y = (float)y;
vp.width = (float)w;
vp.height = (float)h;
Draw::Viewport vp;
vp.MinDepth = 0.0;
vp.MaxDepth = 1.0;
vp.TopLeftX = (float)x;
vp.TopLeftY = (float)y;
vp.Width = (float)w;
vp.Height = (float)h;
// Since we're about to override it.
draw_->FlushState();
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
vkCmdSetViewport(cmd, 0, 1, &vp);
draw_->SetViewports(1, &vp);
}
void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) {
@ -359,18 +359,15 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
// TODO: Should probably use draw_ directly and not go low level
VulkanPushBuffer *push = frameData_[curFrame_].push_;
VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::RENDERPASS_COMMANDBUFFER);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
VkImageView view = overrideImageView_ ? overrideImageView_ : (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE_IMAGEVIEW);
if ((flags & DRAWTEX_KEEP_TEX) == 0)
overrideImageView_ = VK_NULL_HANDLE;
vulkan2D_.BindDescriptorSet(cmd, view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, cur2DPipeline_);
VkDescriptorSet descSet = vulkan2D_.GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
VkBuffer vbuffer;
VkDeviceSize offset = push->Push(vtx, sizeof(vtx), &vbuffer);
vkCmdBindVertexBuffers(cmd, 0, 1, &vbuffer, &offset);
vkCmdDraw(cmd, 4, 1, 0, 0);
renderManager->Draw(cur2DPipeline_, vulkan2D_.GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
}
void FramebufferManagerVulkan::Bind2DShader() {
@ -645,18 +642,6 @@ void FramebufferManagerVulkan::BeginFrameVulkan() {
frame.push_->Reset();
frame.push_->Begin(vulkan_);
if (!useBufferedRendering_) {
// TODO: This hackery should not be necessary. Is it? Need to check.
// We only use a single command buffer in this case.
VkCommandBuffer cmd = vulkan_->GetSurfaceCommandBuffer();
VkRect2D scissor;
scissor.offset = { 0, 0 };
scissor.extent = { (uint32_t)pixelWidth_, (uint32_t)pixelHeight_ };
vkCmdSetScissor(cmd, 0, 1, &scissor);
} else {
// Each render pass will set up scissor again.
}
}
void FramebufferManagerVulkan::EndFrame() {

View file

@ -466,6 +466,7 @@ VkFormat ToVulkanFormat(ReplacedTextureFormat fmt) {
void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceImages) {
entry->status &= ~TexCacheEntry::STATUS_ALPHA_MASK;
VkCommandBuffer cmdInit = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER);
// For the estimate, we assume cluts always point to 8888 for simplicity.
cacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
@ -588,7 +589,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
break;
}
bool allocSuccess = image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
bool allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
if (!allocSuccess && !lowMemoryMode_) {
WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode");
lowMemoryMode_ = true;
@ -607,7 +608,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
scaleFactor = 1;
actualFmt = dstFmt;
allocSuccess = image->CreateDirect(w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping);
}
if (!allocSuccess) {
@ -615,7 +616,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
entry->vkTex = nullptr;
}
} else {
entry->vkTex->texture_->TransitionForUpload();
entry->vkTex->texture_->TransitionForUpload(cmdInit);
}
lastBoundTexture = entry->vkTex;
@ -652,7 +653,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
} else {
if (fakeMipmap) {
LoadTextureLevel(*entry, (uint8_t *)data, stride, level, scaleFactor, dstFmt);
entry->vkTex->texture_->UploadMip(0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
entry->vkTex->texture_->UploadMip(cmdInit, 0, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
break;
} else {
LoadTextureLevel(*entry, (uint8_t *)data, stride, i, scaleFactor, dstFmt);
@ -661,7 +662,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
replacer_.NotifyTextureDecoded(replacedInfo, data, stride, i, mipWidth, mipHeight);
}
}
entry->vkTex->texture_->UploadMip(i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
entry->vkTex->texture_->UploadMip(cmdInit, i, mipWidth, mipHeight, texBuf, bufferOffset, stride / bpp);
}
if (maxLevel == 0) {
@ -674,7 +675,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry, bool replaceIm
}
}
entry->vkTex->texture_->EndCreate();
entry->vkTex->texture_->EndCreate(cmdInit);
gstate_c.SetTextureFullAlpha(entry->GetAlphaStatus() == TexCacheEntry::STATUS_ALPHA_FULL);
gstate_c.SetTextureSimpleAlpha(entry->GetAlphaStatus() != TexCacheEntry::STATUS_ALPHA_UNKNOWN);

View file

@ -27,11 +27,11 @@ VulkanFBO::~VulkanFBO() {
delete depthStencil_;
}
void VulkanFBO::Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
void VulkanFBO::Create(VulkanContext *vulkan, VkCommandBuffer cmd, VkRenderPass rp_compatible, int width, int height, VkFormat color_Format) {
color_ = new VulkanTexture(vulkan);
VkImageCreateFlags flags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
color_->CreateDirect(width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, nullptr);
depthStencil_->CreateDirect(width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, nullptr);
color_->CreateDirect(cmd, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, nullptr);
depthStencil_->CreateDirect(cmd, width, height, 1, VK_FORMAT_D24_UNORM_S8_UINT, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, flags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, nullptr);
VkImageView views[2] = { color_->GetImageView(), depthStencil_->GetImageView() };
@ -334,11 +334,6 @@ VkPipeline Vulkan2D::GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShade
}
}
void Vulkan2D::BindDescriptorSet(VkCommandBuffer cmd, VkImageView tex1, VkSampler sampler1) {
VkDescriptorSet descSet = GetDescriptorSet(tex1, sampler1, VK_NULL_HANDLE, VK_NULL_HANDLE);
vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 0, nullptr);
}
VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code, std::string *error) {
std::vector<uint32_t> spirv;
bool success = GLSLtoSPV(stage, code, spirv, error);

View file

@ -54,7 +54,7 @@ public:
// Depth-format is chosen automatically depending on hardware support.
// Color format will be 32-bit RGBA.
void Create(VulkanContext *vulkan, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
void Create(VulkanContext *vulkan, VkCommandBuffer cmd, VkRenderPass rp_compatible, int width, int height, VkFormat colorFormat);
VulkanTexture *GetColor() { return color_; }
VulkanTexture *GetDepthStencil() { return depthStencil_; }
@ -84,15 +84,12 @@ public:
void Shutdown();
VkPipeline GetPipeline(VkPipelineCache cache, VkRenderPass rp, VkShaderModule vs, VkShaderModule fs);
VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
void BeginFrame();
void EndFrame();
VkDescriptorSet GetDescriptorSet(VkImageView tex1, VkSampler sampler1, VkImageView tex2, VkSampler sampler2);
// Simple way
void BindDescriptorSet(VkCommandBuffer cmd, VkImageView tex1, VkSampler sampler1);
struct Vertex {
float x, y, z;
float u, v;

View file

@ -189,7 +189,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m
g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions);
}
g_Vulkan->InitSurfaceWin32(hInst, hWnd);
if (!g_Vulkan->InitObjects(true)) {
if (!g_Vulkan->InitObjects()) {
Shutdown();
return false;
}
@ -219,10 +219,12 @@ void WindowsVulkanContext::SwapBuffers() {
void WindowsVulkanContext::Resize() {
g_Vulkan->WaitUntilQueueIdle();
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
g_Vulkan->DestroyObjects();
g_Vulkan->ReinitSurfaceWin32();
g_Vulkan->InitObjects(true);
g_Vulkan->InitObjects();
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
}
void WindowsVulkanContext::SwapInterval(int interval) {

View file

@ -105,6 +105,17 @@ inline void CopyFloat3(float dest[3], const float src[3]) {
dest[2] = src[2];
}
inline void CopyFloat4(float dest[3], const float src[3]) {
#ifdef _M_SSE
_mm_storeu_ps(dest, _mm_loadu_ps(src));
#else
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
#endif
}
inline void CopyFloat1To4(float dest[4], const float src) {
#ifdef _M_SSE
_mm_storeu_ps(dest, _mm_set_ss(src));

View file

@ -321,9 +321,10 @@ enum class NativeObject {
BACKBUFFER_COLOR_TEX,
BACKBUFFER_DEPTH_TEX,
FEATURE_LEVEL,
BACKBUFFER_RENDERPASS,
COMPATIBLE_RENDERPASS,
CURRENT_RENDERPASS,
RENDERPASS_COMMANDBUFFER,
INIT_COMMANDBUFFER,
BOUND_TEXTURE_IMAGEVIEW,
RENDER_MANAGER,
};
@ -678,7 +679,7 @@ public:
}
virtual std::string GetInfoString(InfoField info) const = 0;
virtual uintptr_t GetNativeObject(NativeObject obj) const = 0;
virtual uintptr_t GetNativeObject(NativeObject obj) = 0;
virtual void HandleEvent(Event ev, int width, int height, void *param1 = nullptr, void *param2 = nullptr) = 0;

View file

@ -116,7 +116,7 @@ public:
}
}
uintptr_t GetNativeObject(NativeObject obj) const override {
uintptr_t GetNativeObject(NativeObject obj) override {
switch (obj) {
case NativeObject::DEVICE:
return (uintptr_t)device_;

View file

@ -529,7 +529,7 @@ public:
void DrawUP(const void *vdata, int vertexCount) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal);
uintptr_t GetNativeObject(NativeObject obj) const override {
uintptr_t GetNativeObject(NativeObject obj) override {
switch (obj) {
case NativeObject::CONTEXT:
return (uintptr_t)d3d_;

View file

@ -560,7 +560,7 @@ public:
}
}
uintptr_t GetNativeObject(NativeObject obj) const override {
uintptr_t GetNativeObject(NativeObject obj) override {
return 0;
}

File diff suppressed because it is too large Load diff