mirror of
https://github.com/coah80/LegacyVulkEdition.git
synced 2026-06-17 23:01:52 +00:00
448 lines
18 KiB
C++
448 lines
18 KiB
C++
#include "vui_internal.h"
|
|
|
|
namespace vui {
|
|
|
|
uint32_t Renderer::Impl::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
|
VkPhysicalDeviceMemoryProperties memProps;
|
|
vkGetPhysicalDeviceMemoryProperties(physDevice, &memProps);
|
|
for (uint32_t i = 0; i < memProps.memoryTypeCount; i++) {
|
|
if ((typeFilter & (1 << i)) && (memProps.memoryTypes[i].propertyFlags & properties) == properties)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
VkShaderModule Renderer::Impl::createShaderModule(const uint32_t *code, size_t sizeBytes) {
|
|
VkShaderModuleCreateInfo ci{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO};
|
|
ci.codeSize = sizeBytes;
|
|
ci.pCode = code;
|
|
VkShaderModule mod;
|
|
vkCreateShaderModule(device, &ci, nullptr, &mod);
|
|
return mod;
|
|
}
|
|
|
|
void Renderer::Impl::initRenderPass() {
|
|
VkAttachmentDescription colorAttachment{};
|
|
colorAttachment.format = swapchainFormat;
|
|
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
|
|
VkAttachmentReference colorRef{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
|
|
|
VkSubpassDescription subpass{};
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
subpass.colorAttachmentCount = 1;
|
|
subpass.pColorAttachments = &colorRef;
|
|
|
|
VkSubpassDependency dep{};
|
|
dep.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
dep.dstSubpass = 0;
|
|
dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
dep.srcAccessMask = 0;
|
|
dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
|
|
VkRenderPassCreateInfo rpci{VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO};
|
|
rpci.attachmentCount = 1;
|
|
rpci.pAttachments = &colorAttachment;
|
|
rpci.subpassCount = 1;
|
|
rpci.pSubpasses = &subpass;
|
|
rpci.dependencyCount = 1;
|
|
rpci.pDependencies = &dep;
|
|
|
|
vkCreateRenderPass(device, &rpci, nullptr, &renderPass);
|
|
}
|
|
|
|
void Renderer::Impl::initPipeline() {
|
|
VkDescriptorSetLayoutBinding binding{};
|
|
binding.binding = 0;
|
|
binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
binding.descriptorCount = 1;
|
|
binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
|
|
VkDescriptorSetLayoutCreateInfo dslci{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO};
|
|
dslci.bindingCount = 1;
|
|
dslci.pBindings = &binding;
|
|
vkCreateDescriptorSetLayout(device, &dslci, nullptr, &descriptorSetLayout);
|
|
|
|
VkPushConstantRange pushRange{};
|
|
pushRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
|
pushRange.offset = 0;
|
|
pushRange.size = sizeof(float) * 16;
|
|
|
|
VkPipelineLayoutCreateInfo plci{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
|
|
plci.setLayoutCount = 1;
|
|
plci.pSetLayouts = &descriptorSetLayout;
|
|
plci.pushConstantRangeCount = 1;
|
|
plci.pPushConstantRanges = &pushRange;
|
|
vkCreatePipelineLayout(device, &plci, nullptr, &pipelineLayout);
|
|
|
|
VkShaderModule vertMod = createShaderModule(vertShaderSpv, sizeof(vertShaderSpv));
|
|
VkShaderModule fragMod = createShaderModule(fragShaderSpv, sizeof(fragShaderSpv));
|
|
|
|
VkPipelineShaderStageCreateInfo stages[2]{};
|
|
stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
|
|
stages[0].module = vertMod;
|
|
stages[0].pName = "main";
|
|
stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
stages[1].module = fragMod;
|
|
stages[1].pName = "main";
|
|
|
|
VkVertexInputBindingDescription bindingDesc{};
|
|
bindingDesc.binding = 0;
|
|
bindingDesc.stride = sizeof(Vertex);
|
|
bindingDesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
VkVertexInputAttributeDescription attrs[3]{};
|
|
attrs[0].location = 0;
|
|
attrs[0].binding = 0;
|
|
attrs[0].format = VK_FORMAT_R32G32_SFLOAT;
|
|
attrs[0].offset = offsetof(Vertex, pos);
|
|
attrs[1].location = 1;
|
|
attrs[1].binding = 0;
|
|
attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
|
|
attrs[1].offset = offsetof(Vertex, uv);
|
|
attrs[2].location = 2;
|
|
attrs[2].binding = 0;
|
|
attrs[2].format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
attrs[2].offset = offsetof(Vertex, color);
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertexInput{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO};
|
|
vertexInput.vertexBindingDescriptionCount = 1;
|
|
vertexInput.pVertexBindingDescriptions = &bindingDesc;
|
|
vertexInput.vertexAttributeDescriptionCount = 3;
|
|
vertexInput.pVertexAttributeDescriptions = attrs;
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo ia{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO};
|
|
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
VkPipelineViewportStateCreateInfo vps{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
|
|
vps.viewportCount = 1;
|
|
vps.scissorCount = 1;
|
|
|
|
VkPipelineRasterizationStateCreateInfo raster{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO};
|
|
raster.polygonMode = VK_POLYGON_MODE_FILL;
|
|
raster.cullMode = VK_CULL_MODE_NONE;
|
|
raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
raster.lineWidth = 1.0f;
|
|
|
|
VkPipelineMultisampleStateCreateInfo ms{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO};
|
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
VkPipelineColorBlendAttachmentState blendAttachment{};
|
|
blendAttachment.blendEnable = VK_TRUE;
|
|
blendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
blendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
blendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
blendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
blendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
blendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
blendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
|
|
VkPipelineColorBlendStateCreateInfo blend{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO};
|
|
blend.attachmentCount = 1;
|
|
blend.pAttachments = &blendAttachment;
|
|
|
|
VkDynamicState dynStates[] = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
|
|
VkPipelineDynamicStateCreateInfo dyn{VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO};
|
|
dyn.dynamicStateCount = 2;
|
|
dyn.pDynamicStates = dynStates;
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depthStencil{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO};
|
|
|
|
VkGraphicsPipelineCreateInfo pci{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
|
|
pci.stageCount = 2;
|
|
pci.pStages = stages;
|
|
pci.pVertexInputState = &vertexInput;
|
|
pci.pInputAssemblyState = &ia;
|
|
pci.pViewportState = &vps;
|
|
pci.pRasterizationState = &raster;
|
|
pci.pMultisampleState = &ms;
|
|
pci.pColorBlendState = &blend;
|
|
pci.pDynamicState = &dyn;
|
|
pci.pDepthStencilState = &depthStencil;
|
|
pci.layout = pipelineLayout;
|
|
pci.renderPass = renderPass;
|
|
pci.subpass = 0;
|
|
|
|
vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pci, nullptr, &pipeline);
|
|
|
|
vkDestroyShaderModule(device, vertMod, nullptr);
|
|
vkDestroyShaderModule(device, fragMod, nullptr);
|
|
}
|
|
|
|
void Renderer::Impl::initSampler() {
|
|
VkSamplerCreateInfo sci{VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
|
|
sci.magFilter = VK_FILTER_LINEAR;
|
|
sci.minFilter = VK_FILTER_LINEAR;
|
|
sci.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
sci.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
sci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
sci.maxAnisotropy = 1.0f;
|
|
sci.maxLod = 1.0f;
|
|
vkCreateSampler(device, &sci, nullptr, &sampler);
|
|
}
|
|
|
|
void Renderer::Impl::initDescriptorPool() {
|
|
VkDescriptorPoolSize poolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256};
|
|
VkDescriptorPoolCreateInfo dpci{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO};
|
|
dpci.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
|
dpci.maxSets = 256;
|
|
dpci.poolSizeCount = 1;
|
|
dpci.pPoolSizes = &poolSize;
|
|
vkCreateDescriptorPool(device, &dpci, nullptr, &descriptorPool);
|
|
}
|
|
|
|
void Renderer::Impl::initVertexBuffer(uint32_t count) {
|
|
if (vertexBuffer != VK_NULL_HANDLE) {
|
|
vkDestroyBuffer(device, vertexBuffer, nullptr);
|
|
vkFreeMemory(device, vertexMemory, nullptr);
|
|
}
|
|
vertexBufferCapacity = count;
|
|
VkBufferCreateInfo bci{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
|
|
bci.size = sizeof(Vertex) * count;
|
|
bci.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
|
bci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
vkCreateBuffer(device, &bci, nullptr, &vertexBuffer);
|
|
|
|
VkMemoryRequirements memReq;
|
|
vkGetBufferMemoryRequirements(device, vertexBuffer, &memReq);
|
|
|
|
VkMemoryAllocateInfo mai{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
|
|
mai.allocationSize = memReq.size;
|
|
mai.memoryTypeIndex = findMemoryType(memReq.memoryTypeBits,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
vkAllocateMemory(device, &mai, nullptr, &vertexMemory);
|
|
vkBindBufferMemory(device, vertexBuffer, vertexMemory, 0);
|
|
}
|
|
|
|
void Renderer::Impl::uploadTextureData(TextureEntry &tex, int x, int y, int w, int h,
|
|
const void *rgba) {
|
|
VkDeviceSize imageSize = (VkDeviceSize)w * h * 4;
|
|
|
|
VkBuffer stagingBuffer;
|
|
VkDeviceMemory stagingMemory;
|
|
VkBufferCreateInfo bci{VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO};
|
|
bci.size = imageSize;
|
|
bci.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
vkCreateBuffer(device, &bci, nullptr, &stagingBuffer);
|
|
|
|
VkMemoryRequirements memReq;
|
|
vkGetBufferMemoryRequirements(device, stagingBuffer, &memReq);
|
|
VkMemoryAllocateInfo mai{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
|
|
mai.allocationSize = memReq.size;
|
|
mai.memoryTypeIndex = findMemoryType(memReq.memoryTypeBits,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
vkAllocateMemory(device, &mai, nullptr, &stagingMemory);
|
|
vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0);
|
|
|
|
void *mapped;
|
|
vkMapMemory(device, stagingMemory, 0, imageSize, 0, &mapped);
|
|
memcpy(mapped, rgba, imageSize);
|
|
vkUnmapMemory(device, stagingMemory);
|
|
|
|
VkCommandPoolCreateInfo cpci{VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO};
|
|
cpci.queueFamilyIndex = queueFamily;
|
|
cpci.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
|
|
VkCommandPool tmpPool;
|
|
vkCreateCommandPool(device, &cpci, nullptr, &tmpPool);
|
|
|
|
VkCommandBufferAllocateInfo abci{VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO};
|
|
abci.commandPool = tmpPool;
|
|
abci.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
abci.commandBufferCount = 1;
|
|
VkCommandBuffer cmd;
|
|
vkAllocateCommandBuffers(device, &abci, &cmd);
|
|
|
|
VkCommandBufferBeginInfo bbi{VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
bbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
vkBeginCommandBuffer(cmd, &bbi);
|
|
|
|
bool fullImage = (x == 0 && y == 0 && w == tex.width && h == tex.height);
|
|
|
|
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
|
barrier.image = tex.image;
|
|
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
barrier.subresourceRange.levelCount = 1;
|
|
barrier.subresourceRange.layerCount = 1;
|
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
|
|
|
barrier.oldLayout = fullImage ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
barrier.srcAccessMask = 0;
|
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
VkBufferImageCopy region{};
|
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
region.imageSubresource.layerCount = 1;
|
|
region.imageOffset = {x, y, 0};
|
|
region.imageExtent = {(uint32_t)w, (uint32_t)h, 1};
|
|
vkCmdCopyBufferToImage(cmd, stagingBuffer, tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
1, ®ion);
|
|
|
|
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
|
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
|
vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
|
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
|
|
|
vkEndCommandBuffer(cmd);
|
|
VkSubmitInfo si{VK_STRUCTURE_TYPE_SUBMIT_INFO};
|
|
si.commandBufferCount = 1;
|
|
si.pCommandBuffers = &cmd;
|
|
vkQueueSubmit(graphicsQueue, 1, &si, VK_NULL_HANDLE);
|
|
vkQueueWaitIdle(graphicsQueue);
|
|
|
|
vkDestroyCommandPool(device, tmpPool, nullptr);
|
|
vkDestroyBuffer(device, stagingBuffer, nullptr);
|
|
vkFreeMemory(device, stagingMemory, nullptr);
|
|
}
|
|
|
|
int Renderer::Impl::allocTexture(int width, int height, const void *rgba) {
|
|
TextureEntry tex{};
|
|
tex.width = width;
|
|
tex.height = height;
|
|
tex.active = true;
|
|
|
|
VkImageCreateInfo ici{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
|
|
ici.imageType = VK_IMAGE_TYPE_2D;
|
|
ici.format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
ici.extent = {(uint32_t)width, (uint32_t)height, 1};
|
|
ici.mipLevels = 1;
|
|
ici.arrayLayers = 1;
|
|
ici.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
ici.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
ici.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
|
ici.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
vkCreateImage(device, &ici, nullptr, &tex.image);
|
|
|
|
VkMemoryRequirements memReq;
|
|
vkGetImageMemoryRequirements(device, tex.image, &memReq);
|
|
VkMemoryAllocateInfo mai{VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
|
|
mai.allocationSize = memReq.size;
|
|
mai.memoryTypeIndex = findMemoryType(memReq.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
vkAllocateMemory(device, &mai, nullptr, &tex.memory);
|
|
vkBindImageMemory(device, tex.image, tex.memory, 0);
|
|
|
|
VkImageViewCreateInfo vci{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
|
vci.image = tex.image;
|
|
vci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
vci.format = VK_FORMAT_R8G8B8A8_UNORM;
|
|
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
vci.subresourceRange.levelCount = 1;
|
|
vci.subresourceRange.layerCount = 1;
|
|
vkCreateImageView(device, &vci, nullptr, &tex.view);
|
|
|
|
VkDescriptorSetAllocateInfo dsai{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO};
|
|
dsai.descriptorPool = descriptorPool;
|
|
dsai.descriptorSetCount = 1;
|
|
dsai.pSetLayouts = &descriptorSetLayout;
|
|
vkAllocateDescriptorSets(device, &dsai, &tex.descriptorSet);
|
|
|
|
VkDescriptorImageInfo dii{};
|
|
dii.sampler = sampler;
|
|
dii.imageView = tex.view;
|
|
dii.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
|
|
VkWriteDescriptorSet wds{VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET};
|
|
wds.dstSet = tex.descriptorSet;
|
|
wds.dstBinding = 0;
|
|
wds.descriptorCount = 1;
|
|
wds.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
wds.pImageInfo = &dii;
|
|
vkUpdateDescriptorSets(device, 1, &wds, 0, nullptr);
|
|
|
|
if (rgba)
|
|
uploadTextureData(tex, 0, 0, width, height, rgba);
|
|
|
|
int id = -1;
|
|
for (int i = 0; i < (int)textures.size(); i++) {
|
|
if (!textures[i].active) { id = i; break; }
|
|
}
|
|
if (id < 0) {
|
|
id = (int)textures.size();
|
|
textures.push_back(tex);
|
|
} else {
|
|
textures[id] = tex;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
void Renderer::Impl::createWhiteTexture() {
|
|
uint32_t white = 0xFFFFFFFF;
|
|
allocTexture(1, 1, &white);
|
|
}
|
|
|
|
void Renderer::Impl::addQuad(int texId, float x0, float y0, float x1, float y1,
|
|
float u0, float v0, float u1, float v1, Color c) {
|
|
Vertex verts[6];
|
|
float positions[6][2] = {
|
|
{x0, y0}, {x1, y0}, {x1, y1},
|
|
{x0, y0}, {x1, y1}, {x0, y1}
|
|
};
|
|
float uvs[6][2] = {
|
|
{u0, v0}, {u1, v0}, {u1, v1},
|
|
{u0, v0}, {u1, v1}, {u0, v1}
|
|
};
|
|
for (int i = 0; i < 6; i++) {
|
|
float px = positions[i][0], py = positions[i][1];
|
|
currentTransform.transformPoint(px, py);
|
|
verts[i].pos[0] = px;
|
|
verts[i].pos[1] = py;
|
|
verts[i].uv[0] = uvs[i][0];
|
|
verts[i].uv[1] = uvs[i][1];
|
|
verts[i].color[0] = c.r;
|
|
verts[i].color[1] = c.g;
|
|
verts[i].color[2] = c.b;
|
|
verts[i].color[3] = c.a;
|
|
}
|
|
|
|
bool merged = false;
|
|
if (!drawCmds.empty()) {
|
|
auto &last = drawCmds.back();
|
|
bool sameScissor = (!last.hasScissor && scissorStack.empty()) ||
|
|
(last.hasScissor && !scissorStack.empty() &&
|
|
last.scissorX == scissorStack.back().x &&
|
|
last.scissorY == scissorStack.back().y &&
|
|
last.scissorW == scissorStack.back().w &&
|
|
last.scissorH == scissorStack.back().h);
|
|
if (last.textureId == texId && sameScissor) {
|
|
last.vertexCount += 6;
|
|
merged = true;
|
|
}
|
|
}
|
|
|
|
if (!merged) {
|
|
DrawCmd dc;
|
|
dc.textureId = texId;
|
|
dc.vertexOffset = (uint32_t)vertices.size();
|
|
dc.vertexCount = 6;
|
|
dc.hasScissor = !scissorStack.empty();
|
|
if (dc.hasScissor) {
|
|
dc.scissorX = scissorStack.back().x;
|
|
dc.scissorY = scissorStack.back().y;
|
|
dc.scissorW = scissorStack.back().w;
|
|
dc.scissorH = scissorStack.back().h;
|
|
}
|
|
drawCmds.push_back(dc);
|
|
}
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
vertices.push_back(verts[i]);
|
|
}
|
|
|
|
} // namespace vui
|