Add 2D Batch renderer
This commit is contained in:
@@ -170,6 +170,7 @@
|
||||
<ClCompile Include="src\copium\core\Vulkan.cpp" />
|
||||
<ClCompile Include="src\copium\core\Window.cpp" />
|
||||
<ClCompile Include="src\copium\mesh\Mesh.cpp" />
|
||||
<ClCompile Include="src\copium\renderer\Renderer.cpp" />
|
||||
<ClCompile Include="src\copium\sampler\ColorAttachment.cpp" />
|
||||
<ClCompile Include="src\copium\buffer\CommandBuffer.cpp" />
|
||||
<ClCompile Include="src\copium\buffer\CommandBufferScoped.cpp" />
|
||||
@@ -198,11 +199,11 @@
|
||||
<ClCompile Include="src\copium\mesh\VertexPassthrough.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\copium\core\VulkanCore.h" />
|
||||
<ClInclude Include="src\copium\core\Device.h" />
|
||||
<ClInclude Include="src\copium\core\Vulkan.h" />
|
||||
<ClInclude Include="src\copium\core\Window.h" />
|
||||
<ClInclude Include="src\copium\mesh\Mesh.h" />
|
||||
<ClInclude Include="src\copium\renderer\Renderer.h" />
|
||||
<ClInclude Include="src\copium\sampler\DepthAttachment.h" />
|
||||
<ClInclude Include="src\copium\core\Application.h" />
|
||||
<ClInclude Include="src\copium\sampler\ColorAttachment.h" />
|
||||
@@ -236,6 +237,8 @@
|
||||
<ItemGroup>
|
||||
<None Include="res\shaders\passthrough.frag" />
|
||||
<None Include="res\shaders\passthrough.vert" />
|
||||
<None Include="res\shaders\renderer.frag" />
|
||||
<None Include="res\shaders\renderer.vert" />
|
||||
<None Include="res\shaders\shader.frag" />
|
||||
<None Include="res\shaders\shader.vert" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -111,6 +111,9 @@
|
||||
<ClCompile Include="src\copium\core\Vulkan.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\copium\renderer\Renderer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\copium\sampler\DepthAttachment.h">
|
||||
@@ -212,7 +215,7 @@
|
||||
<ClInclude Include="src\copium\core\Device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="src\copium\core\VulkanCore.h">
|
||||
<ClInclude Include="src\copium\renderer\Renderer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -221,5 +224,7 @@
|
||||
<None Include="res\shaders\shader.vert" />
|
||||
<None Include="res\shaders\passthrough.frag" />
|
||||
<None Include="res\shaders\passthrough.vert" />
|
||||
<None Include="res\shaders\renderer.frag" />
|
||||
<None Include="res\shaders\renderer.vert" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,52 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D texSamplers[32];
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
layout(location = 2) in flat int fragTexIndex;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
vec4 TextureColor()
|
||||
{
|
||||
if(fragTexIndex == 0) return texture(texSamplers[0], fragTexCoord);
|
||||
if(fragTexIndex == 1) return texture(texSamplers[1], fragTexCoord);
|
||||
if(fragTexIndex == 2) return texture(texSamplers[2], fragTexCoord);
|
||||
if(fragTexIndex == 3) return texture(texSamplers[3], fragTexCoord);
|
||||
if(fragTexIndex == 4) return texture(texSamplers[4], fragTexCoord);
|
||||
if(fragTexIndex == 5) return texture(texSamplers[5], fragTexCoord);
|
||||
if(fragTexIndex == 6) return texture(texSamplers[6], fragTexCoord);
|
||||
if(fragTexIndex == 7) return texture(texSamplers[7], fragTexCoord);
|
||||
if(fragTexIndex == 8) return texture(texSamplers[8], fragTexCoord);
|
||||
if(fragTexIndex == 9) return texture(texSamplers[9], fragTexCoord);
|
||||
if(fragTexIndex == 10) return texture(texSamplers[10], fragTexCoord);
|
||||
if(fragTexIndex == 11) return texture(texSamplers[11], fragTexCoord);
|
||||
if(fragTexIndex == 12) return texture(texSamplers[12], fragTexCoord);
|
||||
if(fragTexIndex == 13) return texture(texSamplers[13], fragTexCoord);
|
||||
if(fragTexIndex == 14) return texture(texSamplers[14], fragTexCoord);
|
||||
if(fragTexIndex == 15) return texture(texSamplers[15], fragTexCoord);
|
||||
if(fragTexIndex == 16) return texture(texSamplers[16], fragTexCoord);
|
||||
if(fragTexIndex == 17) return texture(texSamplers[17], fragTexCoord);
|
||||
if(fragTexIndex == 18) return texture(texSamplers[18], fragTexCoord);
|
||||
if(fragTexIndex == 19) return texture(texSamplers[19], fragTexCoord);
|
||||
if(fragTexIndex == 20) return texture(texSamplers[20], fragTexCoord);
|
||||
if(fragTexIndex == 21) return texture(texSamplers[21], fragTexCoord);
|
||||
if(fragTexIndex == 22) return texture(texSamplers[22], fragTexCoord);
|
||||
if(fragTexIndex == 23) return texture(texSamplers[23], fragTexCoord);
|
||||
if(fragTexIndex == 24) return texture(texSamplers[24], fragTexCoord);
|
||||
if(fragTexIndex == 25) return texture(texSamplers[25], fragTexCoord);
|
||||
if(fragTexIndex == 26) return texture(texSamplers[26], fragTexCoord);
|
||||
if(fragTexIndex == 27) return texture(texSamplers[27], fragTexCoord);
|
||||
if(fragTexIndex == 28) return texture(texSamplers[28], fragTexCoord);
|
||||
if(fragTexIndex == 29) return texture(texSamplers[29], fragTexCoord);
|
||||
if(fragTexIndex == 30) return texture(texSamplers[30], fragTexCoord);
|
||||
if(fragTexIndex == 31) return texture(texSamplers[31], fragTexCoord);
|
||||
return vec4(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0) * TextureColor();
|
||||
// outColor = vec4(fragTexCoord, 0.0, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 2) in vec2 inTexCoord;
|
||||
layout(location = 3) in int inTexIndex;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
layout(location = 2) out int fragTexIndex;
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(inPosition, 1.0);
|
||||
fragColor = inColor;
|
||||
fragTexCoord = inTexCoord;
|
||||
fragTexIndex = inTexIndex;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 441 KiB |
@@ -18,4 +18,10 @@ namespace Copium
|
||||
{
|
||||
vkCmdDrawIndexed(commandBuffer, indexCount, 1, 0, 0, 0);
|
||||
}
|
||||
|
||||
void IndexBuffer::Draw(const CommandBuffer& commandBuffer, int indices)
|
||||
{
|
||||
CP_ASSERT(indices >= 0 && indices < indexCount, "Draw : amount of indices is out of range");
|
||||
vkCmdDrawIndexed(commandBuffer, indices, 1, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -17,5 +17,6 @@ namespace Copium
|
||||
|
||||
void Bind(const CommandBuffer& commandBuffer);
|
||||
void Draw(const CommandBuffer& commandBuffer);
|
||||
void Draw(const CommandBuffer& commandBuffer, int indices);
|
||||
};
|
||||
}
|
||||
@@ -56,6 +56,7 @@ namespace Copium
|
||||
InitializeDescriptorSets();
|
||||
InitializeMesh();
|
||||
InitializeCommandBuffer();
|
||||
InitializeRenderer();
|
||||
}
|
||||
|
||||
Application::~Application()
|
||||
@@ -99,6 +100,7 @@ namespace Copium
|
||||
void Application::InitializeTextureSampler()
|
||||
{
|
||||
texture2D = std::make_unique<Texture2D>(*vulkan, "res/textures/texture.png");
|
||||
texture2D2 = std::make_unique<Texture2D>(*vulkan, "res/textures/texture2.png");
|
||||
}
|
||||
|
||||
void Application::InitializeUniformBuffer()
|
||||
@@ -145,6 +147,11 @@ namespace Copium
|
||||
commandBuffer = std::make_unique<CommandBuffer>(*vulkan, CommandBuffer::Type::Dynamic);
|
||||
}
|
||||
|
||||
void Application::InitializeRenderer()
|
||||
{
|
||||
renderer = std::make_unique<Renderer>(*vulkan, framebuffer->GetRenderPass(), *descriptorPool);
|
||||
}
|
||||
|
||||
void Application::RecordCommandBuffer()
|
||||
{
|
||||
commandBuffer->Begin();
|
||||
@@ -160,6 +167,18 @@ namespace Copium
|
||||
mesh->Bind(*commandBuffer);
|
||||
mesh->Render(*commandBuffer);
|
||||
|
||||
renderer->Begin(*commandBuffer);
|
||||
for (int y = 0; y < 10; y++)
|
||||
{
|
||||
for (int x = 0; x < 10; x++)
|
||||
{
|
||||
renderer->Quad(glm::vec2(-1 + x * 0.2, -1 + y * 0.2), glm::vec2(-1 + (x + 0.5) * 0.2, -1 + (y + 0.5) * 0.2), glm::vec3{x * 0.1, y * 0.1, 1.0});
|
||||
}
|
||||
}
|
||||
renderer->Quad(glm::vec2(-0.5, -0.5), glm::vec2{-0.1, 0.5}, *texture2D);
|
||||
renderer->Quad(glm::vec2(0.1, -0.5), glm::vec2{0.5, 0.5}, *texture2D2);
|
||||
renderer->End();
|
||||
|
||||
framebuffer->Unbind(*commandBuffer);
|
||||
|
||||
vulkan->GetSwapChain().BeginFrameBuffer(*commandBuffer);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "copium/pipeline/DescriptorSet.h"
|
||||
#include "copium/pipeline/Pipeline.h"
|
||||
#include "copium/sampler/Texture2D.h"
|
||||
#include "copium/renderer/Renderer.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
@@ -23,6 +24,7 @@ namespace Copium
|
||||
std::unique_ptr<Instance> instance;
|
||||
std::unique_ptr<Framebuffer> framebuffer;
|
||||
std::unique_ptr<Texture2D> texture2D;
|
||||
std::unique_ptr<Texture2D> texture2D2;
|
||||
std::unique_ptr<UniformBuffer> shaderUniformBuffer;
|
||||
std::unique_ptr<DescriptorPool> descriptorPool;
|
||||
std::unique_ptr<DescriptorSet> descriptorSet;
|
||||
@@ -32,6 +34,7 @@ namespace Copium
|
||||
std::unique_ptr<Mesh> mesh;
|
||||
std::unique_ptr<Mesh> meshPassthrough;
|
||||
std::unique_ptr<CommandBuffer> commandBuffer;
|
||||
std::unique_ptr<Renderer> renderer;
|
||||
|
||||
public:
|
||||
Application();
|
||||
@@ -47,6 +50,7 @@ namespace Copium
|
||||
void InitializeGraphicsPipeline();
|
||||
void InitializeMesh();
|
||||
void InitializeCommandBuffer();
|
||||
void InitializeRenderer();
|
||||
|
||||
void RecordCommandBuffer();
|
||||
void UpdateUniformBuffer();
|
||||
|
||||
@@ -35,21 +35,49 @@ namespace Copium
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorSet::AddSampler(const Sampler& sampler, uint32_t binding)
|
||||
void DescriptorSet::AddSampler(const Sampler& sampler, uint32_t binding, int arrayIndex)
|
||||
{
|
||||
for (size_t i = 0; i < descriptorSets.size(); ++i)
|
||||
{
|
||||
AddSampler(sampler, binding, i, arrayIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void DescriptorSet::AddSampler(const Sampler& sampler, uint32_t binding, int index, int arrayIndex)
|
||||
{
|
||||
CP_ASSERT(index >= 0 && index < descriptorSets.size(), "AddSampler : index is out of range");
|
||||
VkDescriptorImageInfo imageInfo = sampler.GetDescriptorImageInfo(index);
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = descriptorSets[index];
|
||||
descriptorWrite.dstBinding = binding;
|
||||
descriptorWrite.dstArrayElement = arrayIndex;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.pBufferInfo = nullptr;
|
||||
descriptorWrite.pImageInfo = &imageInfo;
|
||||
descriptorWrite.pTexelBufferView = nullptr;
|
||||
vkUpdateDescriptorSets(vulkan.GetDevice(), 1, &descriptorWrite, 0, nullptr);
|
||||
}
|
||||
|
||||
void DescriptorSet::AddSamplers(const std::vector<const Sampler*>& samplers, uint32_t binding)
|
||||
{
|
||||
for (size_t i = 0; i < descriptorSets.size(); ++i) {
|
||||
VkDescriptorImageInfo imageInfo = sampler.GetDescriptorImageInfo(i);
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = descriptorSets[i];
|
||||
descriptorWrite.dstBinding = binding;
|
||||
descriptorWrite.dstArrayElement = 0;
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
descriptorWrite.pBufferInfo = nullptr;
|
||||
descriptorWrite.pImageInfo = &imageInfo;
|
||||
descriptorWrite.pTexelBufferView = nullptr;
|
||||
vkUpdateDescriptorSets(vulkan.GetDevice(), 1, &descriptorWrite, 0, nullptr);
|
||||
std::vector<VkWriteDescriptorSet> descriptorWrites{samplers.size()};
|
||||
for (size_t j = 0; j < samplers.size(); j++)
|
||||
{
|
||||
VkDescriptorImageInfo imageInfo = samplers[j]->GetDescriptorImageInfo(i);
|
||||
descriptorWrites[j].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrites[j].dstSet = descriptorSets[i];
|
||||
descriptorWrites[j].dstBinding = binding;
|
||||
descriptorWrites[j].dstArrayElement = j;
|
||||
descriptorWrites[j].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrites[j].descriptorCount = 1;
|
||||
descriptorWrites[j].pBufferInfo = nullptr;
|
||||
descriptorWrites[j].pImageInfo = &imageInfo;
|
||||
descriptorWrites[j].pTexelBufferView = nullptr;
|
||||
}
|
||||
vkUpdateDescriptorSets(vulkan.GetDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace Copium
|
||||
~DescriptorSet();
|
||||
|
||||
void AddUniform(const UniformBuffer& uniformBuffer, uint32_t binding);
|
||||
void AddSampler(const Sampler& sampler, uint32_t binding);
|
||||
void AddSampler(const Sampler& sampler, uint32_t binding, int arrayIndex = 0);
|
||||
void AddSampler(const Sampler& sampler, uint32_t binding, int index, int arrayIndex = 0);
|
||||
void AddSamplers(const std::vector<const Sampler*>& sampler, uint32_t binding);
|
||||
operator VkDescriptorSet() const;
|
||||
};
|
||||
}
|
||||
@@ -142,8 +142,8 @@ namespace Copium
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depthStencilCreateInfo{};
|
||||
depthStencilCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depthStencilCreateInfo.depthTestEnable = VK_TRUE;
|
||||
depthStencilCreateInfo.depthWriteEnable = VK_TRUE;
|
||||
depthStencilCreateInfo.depthTestEnable = creator.depthTest ? VK_TRUE : VK_FALSE;
|
||||
depthStencilCreateInfo.depthWriteEnable = creator.depthTest ? VK_TRUE : VK_FALSE;
|
||||
depthStencilCreateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||
depthStencilCreateInfo.depthBoundsTestEnable = VK_FALSE;
|
||||
depthStencilCreateInfo.minDepthBounds = 0.0f;
|
||||
@@ -155,9 +155,9 @@ namespace Copium
|
||||
|
||||
VkPipelineColorBlendAttachmentState colorBlendAttachment{}; // TODO: Add to PipelineCreator
|
||||
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT;
|
||||
VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT |
|
||||
VK_COLOR_COMPONENT_A_BIT;
|
||||
colorBlendAttachment.blendEnable = VK_FALSE;
|
||||
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
|
||||
@@ -35,4 +35,9 @@ namespace Copium
|
||||
{
|
||||
frontFace = cullFrontFace;
|
||||
}
|
||||
|
||||
void PipelineCreator::SetDepthTest(bool depthTest)
|
||||
{
|
||||
this->depthTest = depthTest;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace Copium
|
||||
VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
VkFrontFace frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
bool depthTest = true;
|
||||
|
||||
public:
|
||||
PipelineCreator(VkRenderPass renderPass, const std::string& vertexShader, const std::string& fragmentShader);
|
||||
@@ -37,5 +38,6 @@ namespace Copium
|
||||
void SetPrimitiveTopology(VkPrimitiveTopology primitiveTopology);
|
||||
void SetCullMode(VkCullModeFlags flags);
|
||||
void SetCullFrontFace(VkFrontFace cullFrontFace);
|
||||
void SetDepthTest(bool depthTest);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "copium/renderer/Renderer.h"
|
||||
|
||||
#include "copium/core/SwapChain.h"
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
static constexpr int QUAD_COUNT = 10000;
|
||||
static constexpr int MAX_NUM_VERTICES = 4 * QUAD_COUNT;
|
||||
static constexpr int MAX_NUM_INDICES = 6 * QUAD_COUNT;
|
||||
static constexpr int MAX_NUM_TEXTURES = 32;
|
||||
|
||||
Renderer::Renderer(Vulkan& vulkan, VkRenderPass renderPass, DescriptorPool& descriptorPool)
|
||||
: vulkan{vulkan},
|
||||
descriptorPool{vulkan},
|
||||
ibo{vulkan, MAX_NUM_INDICES},
|
||||
emptyTexture{vulkan, {0, 0, 0, 0}, 1, 1},
|
||||
samplers{MAX_NUM_TEXTURES, &emptyTexture}
|
||||
{
|
||||
CP_ASSERT(MAX_NUM_INDICES < std::numeric_limits<uint16_t>::max(), "Renderer : Maximum number of indices too big");
|
||||
|
||||
|
||||
std::vector<uint16_t> indices;
|
||||
indices.resize(MAX_NUM_INDICES);
|
||||
for (int i = 0; i < QUAD_COUNT; i++)
|
||||
{
|
||||
indices[i * 6] = i * 4;
|
||||
indices[i * 6 + 1] = i * 4 + 1;
|
||||
indices[i * 6 + 2] = i * 4 + 2;
|
||||
indices[i * 6 + 3] = i * 4;
|
||||
indices[i * 6 + 4] = i * 4 + 2;
|
||||
indices[i * 6 + 5] = i * 4 + 3;
|
||||
}
|
||||
ibo.UpdateStaging(indices.data());
|
||||
PipelineCreator creator{renderPass, "res/shaders/renderer.vert", "res/shaders/renderer.frag"};
|
||||
creator.SetVertexDescriptor(Vertex::GetDescriptor());
|
||||
creator.AddDescriptorSetLayoutBinding(0, 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, MAX_NUM_TEXTURES, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
creator.SetDepthTest(false);
|
||||
graphicsPipeline = std::make_unique<Pipeline>(vulkan, creator);
|
||||
}
|
||||
|
||||
void Renderer::Quad(const glm::vec2& from, const glm::vec2& to, const glm::vec3& color)
|
||||
{
|
||||
AllocateQuad();
|
||||
AddVertex(from, color, -1, glm::vec2{0, 0});
|
||||
AddVertex(glm::vec2{to.x, from.y}, color, -1, glm::vec2{0, 0});
|
||||
AddVertex(to, color, -1, glm::vec2{0, 0});
|
||||
AddVertex(glm::vec2{from.x, to.y}, color, -1, glm::vec2{0, 0});
|
||||
}
|
||||
|
||||
|
||||
void Renderer::Quad(const glm::vec2& from, const glm::vec2& to, const Sampler& sampler, const glm::vec2& texCoord1, const glm::vec2& texCoord2)
|
||||
{
|
||||
AllocateQuad();
|
||||
int texIndex = AllocateSampler(sampler);
|
||||
AddVertex(from, glm::vec3{1,1,1}, texIndex, texCoord1);
|
||||
AddVertex(glm::vec2{to.x, from.y}, glm::vec3{1,1,1}, texIndex, glm::vec2{texCoord2.x, texCoord1.y});
|
||||
AddVertex(to, glm::vec3{1,1,1}, texIndex, texCoord2);
|
||||
AddVertex(glm::vec2{from.x, to.y}, glm::vec3{1,1,1}, texIndex, glm::vec2{texCoord1.x, texCoord2.y});
|
||||
}
|
||||
|
||||
void Renderer::AddVertex(const glm::vec2& position, const glm::vec3& color, int texindex, const glm::vec2& texCoord)
|
||||
{
|
||||
Vertex* vertex = (Vertex*)mappedVertexBuffer;
|
||||
vertex->position = position;
|
||||
vertex->color = color;
|
||||
vertex->texCoord = texCoord;
|
||||
vertex->texIndex = texindex;
|
||||
mappedVertexBuffer = (Vertex*)mappedVertexBuffer + 1;
|
||||
}
|
||||
|
||||
void Renderer::Begin(CommandBuffer& commandBuffer)
|
||||
{
|
||||
graphicsPipeline->Bind(commandBuffer);
|
||||
ibo.Bind(commandBuffer);
|
||||
vboIndex = -1;
|
||||
NextVertexBuffer();
|
||||
currentCommandBuffer = &commandBuffer;
|
||||
}
|
||||
|
||||
void Renderer::End()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
int Renderer::AllocateSampler(const Sampler& sampler)
|
||||
{
|
||||
for (size_t i = 0; i < texturesUsed; i++)
|
||||
{
|
||||
if (*samplers[i] == sampler)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if (texturesUsed == MAX_NUM_TEXTURES)
|
||||
{
|
||||
Flush();
|
||||
NextVertexBuffer();
|
||||
}
|
||||
currentDescriptorSet->AddSampler(sampler, 0, vulkan.GetSwapChain().GetFlightIndex(), texturesUsed);
|
||||
samplers[texturesUsed] = &sampler;
|
||||
texturesUsed++;
|
||||
return texturesUsed - 1;
|
||||
}
|
||||
|
||||
void Renderer::AllocateQuad()
|
||||
{
|
||||
if (vertexCount + 4 > MAX_NUM_VERTICES)
|
||||
{
|
||||
Flush();
|
||||
NextVertexBuffer();
|
||||
}
|
||||
vertexCount += 4;
|
||||
indexCount += 6;
|
||||
}
|
||||
|
||||
void Renderer::Flush()
|
||||
{
|
||||
currentVertexBuffer->Unmap();
|
||||
VkBuffer buffer = *currentVertexBuffer;
|
||||
VkDeviceSize offset = currentVertexBuffer->GetPosition(vulkan.GetSwapChain().GetFlightIndex());
|
||||
vkCmdBindVertexBuffers(*currentCommandBuffer, 0, 1, &buffer, &offset);
|
||||
graphicsPipeline->SetDescriptorSet(0, *currentDescriptorSet);
|
||||
graphicsPipeline->BindDescriptorSets(*currentCommandBuffer);
|
||||
ibo.Draw(*currentCommandBuffer, indexCount);
|
||||
}
|
||||
|
||||
void Renderer::NextVertexBuffer()
|
||||
{
|
||||
vboIndex++;
|
||||
if (vboIndex >= vbos.size())
|
||||
{
|
||||
// Allocate new buffer since all existing buffers are full
|
||||
vbos.emplace_back(std::make_unique<Buffer>(vulkan, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(Vertex) * MAX_NUM_VERTICES, SwapChain::MAX_FRAMES_IN_FLIGHT));
|
||||
descriptorSets.emplace_back(std::make_unique<DescriptorSet>(vulkan, descriptorPool, graphicsPipeline->GetDescriptorSetLayout(0)));
|
||||
descriptorSets.back()->AddSamplers(samplers, 0);
|
||||
}
|
||||
currentVertexBuffer = vbos[vboIndex].get();
|
||||
currentDescriptorSet = descriptorSets[vboIndex].get();
|
||||
mappedVertexBuffer = (char*)currentVertexBuffer->Map() + currentVertexBuffer->GetPosition(vulkan.GetSwapChain().GetFlightIndex());
|
||||
vertexCount = 0;
|
||||
indexCount = 0;
|
||||
texturesUsed = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "copium/buffer/CommandBuffer.h"
|
||||
#include "copium/buffer/IndexBuffer.h"
|
||||
#include "copium/buffer/VertexBuffer.h"
|
||||
#include "copium/core/Vulkan.h"
|
||||
#include "copium/pipeline/Pipeline.h"
|
||||
#include "copium/pipeline/PipelineCreator.h"
|
||||
#include "copium/sampler/Texture2D.h"
|
||||
#include "copium/util/Common.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
class Renderer
|
||||
{
|
||||
CP_DELETE_COPY_AND_MOVE_CTOR(Renderer);
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec2 position;
|
||||
glm::vec3 color;
|
||||
glm::vec2 texCoord;
|
||||
int8_t texIndex;
|
||||
|
||||
static VertexDescriptor GetDescriptor()
|
||||
{
|
||||
VertexDescriptor descriptor{};
|
||||
descriptor.AddAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, position), sizeof(Vertex));
|
||||
descriptor.AddAttribute(0, 1, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, color), sizeof(Vertex));
|
||||
descriptor.AddAttribute(0, 2, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, texCoord), sizeof(Vertex));
|
||||
descriptor.AddAttribute(0, 3, VK_FORMAT_R8_SINT, offsetof(Vertex, texIndex), sizeof(Vertex));
|
||||
return descriptor;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
Vulkan& vulkan;
|
||||
|
||||
DescriptorPool descriptorPool;
|
||||
IndexBuffer ibo;
|
||||
Texture2D emptyTexture;
|
||||
std::unique_ptr<Pipeline> graphicsPipeline;
|
||||
std::vector<std::unique_ptr<Buffer>> vbos;
|
||||
std::vector<std::unique_ptr<DescriptorSet>> descriptorSets;
|
||||
|
||||
// Temporary data during a render
|
||||
CommandBuffer* currentCommandBuffer;
|
||||
Buffer* currentVertexBuffer;
|
||||
DescriptorSet* currentDescriptorSet;
|
||||
std::vector<const Sampler*> samplers;
|
||||
int vboIndex;
|
||||
int vertexCount;
|
||||
int indexCount;
|
||||
void* mappedVertexBuffer;
|
||||
int texturesUsed;
|
||||
public:
|
||||
Renderer(Vulkan& vulkan, VkRenderPass renderPass, DescriptorPool& descriptorPool);
|
||||
|
||||
void Quad(const glm::vec2& from, const glm::vec2& to, const glm::vec3& color = glm::vec3{1, 1, 1});
|
||||
void Quad(const glm::vec2& from, const glm::vec2& to, const Sampler& sampler, const glm::vec2& texCoord1 = glm::vec2{0, 0}, const glm::vec2& texCoord2 = glm::vec2{1, 1});
|
||||
|
||||
void Begin(CommandBuffer& commandBuffer);
|
||||
void End();
|
||||
private:
|
||||
|
||||
int AllocateSampler(const Sampler& sampler);
|
||||
void AllocateQuad();
|
||||
void Flush();
|
||||
void NextVertexBuffer();
|
||||
|
||||
void AddVertex(const glm::vec2& position, const glm::vec3& color, int texindex, const glm::vec2& texCoord);
|
||||
};
|
||||
}
|
||||
@@ -39,4 +39,9 @@ namespace Copium
|
||||
|
||||
CP_VK_ASSERT(vkCreateSampler(vulkan.GetDevice(), &createInfo, nullptr, &sampler), "InitializeSampler : Failed to initialize texture sampler");
|
||||
}
|
||||
|
||||
Sampler::operator VkSampler() const
|
||||
{
|
||||
return sampler;
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace Copium
|
||||
virtual ~Sampler();
|
||||
|
||||
virtual VkDescriptorImageInfo GetDescriptorImageInfo(int index) const = 0;
|
||||
operator VkSampler() const;
|
||||
private:
|
||||
void InitializeSampler();
|
||||
};
|
||||
|
||||
@@ -10,7 +10,15 @@ namespace Copium
|
||||
Texture2D::Texture2D(Vulkan& vulkan, const std::string& filename)
|
||||
: Sampler{vulkan}
|
||||
{
|
||||
InitializeTextureImage(filename);
|
||||
CP_DEBUG("Texture2D : Loading texture file: %s", filename.c_str());
|
||||
InitializeTextureImageFromFile(filename);
|
||||
}
|
||||
|
||||
Texture2D::Texture2D(Vulkan& vulkan, const std::vector<uint8_t>& rgbaData, int width, int height)
|
||||
: Sampler{vulkan}
|
||||
{
|
||||
CP_ASSERT(rgbaData.size() == width * height * 4, "rgbaData has invalid size, should be equal to width * height * 4 (%d) actually is %d", width * height * 4, rgbaData.size());
|
||||
InitializeTextureImageFromData((void*)rgbaData.data(), width, height);
|
||||
}
|
||||
|
||||
Texture2D::~Texture2D()
|
||||
@@ -30,7 +38,7 @@ namespace Copium
|
||||
return imageInfo;
|
||||
}
|
||||
|
||||
void Texture2D::InitializeTextureImage(const std::string& filename)
|
||||
void Texture2D::InitializeTextureImageFromFile(const std::string& filename)
|
||||
{
|
||||
int texWidth;
|
||||
int texHeight;
|
||||
@@ -39,16 +47,22 @@ namespace Copium
|
||||
|
||||
CP_ASSERT(pixels, "InitializeTextureImage : Failed to load texture image");
|
||||
|
||||
VkDeviceSize bufferSize = texWidth * texHeight * 4;
|
||||
InitializeTextureImageFromData((void*)pixels, texWidth, texHeight);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
}
|
||||
|
||||
void Texture2D::InitializeTextureImageFromData(void* rgbaData, int width, int height)
|
||||
{
|
||||
VkDeviceSize bufferSize = width * height * 4;
|
||||
Buffer stagingBuffer{vulkan, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, bufferSize, 1};
|
||||
void* data = stagingBuffer.Map();
|
||||
memcpy(data, pixels, bufferSize);
|
||||
memcpy(data, rgbaData, bufferSize);
|
||||
stagingBuffer.Unmap();
|
||||
stbi_image_free(pixels);
|
||||
|
||||
Image::InitializeImage(vulkan, texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
||||
Image::InitializeImage(vulkan, width, height, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &image, &imageMemory);
|
||||
Image::TransitionImageLayout(vulkan, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
Image::CopyBufferToImage(vulkan, stagingBuffer, image, texWidth, texHeight);
|
||||
Image::CopyBufferToImage(vulkan, stagingBuffer, image, width, height);
|
||||
Image::TransitionImageLayout(vulkan, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
imageView = Image::InitializeImageView(vulkan, image, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ namespace Copium
|
||||
VkImageView imageView;
|
||||
public:
|
||||
Texture2D(Vulkan& vulkan, const std::string& filename);
|
||||
Texture2D(Vulkan& vulkan, const std::vector<uint8_t>& rgbaData, int width, int height);
|
||||
~Texture2D() override;
|
||||
|
||||
VkDescriptorImageInfo GetDescriptorImageInfo(int index) const override;
|
||||
private:
|
||||
void InitializeTextureImage(const std::string& filename);
|
||||
void InitializeTextureImageFromFile(const std::string& filename);
|
||||
void InitializeTextureImageFromData(void* rgbaData, int width, int height);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,23 +10,23 @@
|
||||
#define CP_TERM_GRAY "\x1B[90m"
|
||||
#define CP_TERM_CLEAR "\033[0m"
|
||||
|
||||
#define CP_DEBUG(format, ...) std::cout << CP_TERM_GRAY << "[DBG] " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_INFO(format, ...) std::cout << "[INF] " << Copium::StringFormat(format, __VA_ARGS__) << std::endl
|
||||
#define CP_WARN(format, ...) std::cout << CP_TERM_YELLOW << "[WRN] " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_ERR(format, ...) std::cout << CP_TERM_RED << "[ERR] " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_DEBUG(format, ...) std::cout << CP_TERM_GRAY << "[DBG] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_INFO(format, ...) std::cout << "[INF] " << Copium::String::Format(format, __VA_ARGS__) << std::endl
|
||||
#define CP_WARN(format, ...) std::cout << CP_TERM_YELLOW << "[WRN] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_ERR(format, ...) std::cout << CP_TERM_RED << "[ERR] " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
|
||||
// Continue traces, will not print the [XXX] tag before the log
|
||||
#define CP_DEBUG_CONT(format, ...) std::cout << CP_TERM_GRAY << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_INFO_CONT(format, ...) std::cout << " " << Copium::StringFormat(format, __VA_ARGS__) << std::endl
|
||||
#define CP_WARN_CONT(format, ...) std::cout << CP_TERM_YELLOW << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_ERR_CONT(format, ...) std::cout << CP_TERM_RED << " " << Copium::StringFormat(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_DEBUG_CONT(format, ...) std::cout << CP_TERM_GRAY << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_INFO_CONT(format, ...) std::cout << " " << Copium::String::Format(format, __VA_ARGS__) << std::endl
|
||||
#define CP_WARN_CONT(format, ...) std::cout << CP_TERM_YELLOW << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
#define CP_ERR_CONT(format, ...) std::cout << CP_TERM_RED << " " << Copium::String::Format(format, __VA_ARGS__) << CP_TERM_CLEAR << std::endl
|
||||
|
||||
#define CP_UNIMPLEMENTED() CP_WARN("%s is unimplemented", __FUNCTION__)
|
||||
#define CP_ABORT(format, ...) \
|
||||
do \
|
||||
{ \
|
||||
CP_ERR(format, __VA_ARGS__); \
|
||||
throw std::runtime_error(Copium::StringFormat(format, __VA_ARGS__)); \
|
||||
throw std::runtime_error(Copium::String::Format(format, __VA_ARGS__)); \
|
||||
} while(false)
|
||||
#define CP_ASSERT(Function, format, ...) \
|
||||
do \
|
||||
@@ -34,7 +34,7 @@
|
||||
if(!(Function)) \
|
||||
{ \
|
||||
CP_ERR(format, __VA_ARGS__); \
|
||||
throw std::runtime_error(Copium::StringFormat(format, __VA_ARGS__)); \
|
||||
throw std::runtime_error(Copium::String::Format(format, __VA_ARGS__)); \
|
||||
} \
|
||||
} while(false)
|
||||
#define CP_VK_ASSERT(Function, format, ...) \
|
||||
@@ -43,7 +43,7 @@
|
||||
if(Function != VK_SUCCESS) \
|
||||
{ \
|
||||
CP_ERR(format, __VA_ARGS__); \
|
||||
throw VulkanException(Copium::StringFormat(format, __VA_ARGS__)); \
|
||||
throw VulkanException(Copium::String::Format(format, __VA_ARGS__)); \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
@@ -57,13 +57,18 @@
|
||||
|
||||
namespace Copium
|
||||
{
|
||||
template<typename ... Args>
|
||||
std::string StringFormat(const std::string& format, Args... args)
|
||||
class String
|
||||
{
|
||||
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
||||
CP_ASSERT(size > 0, "StringFormat : Error during formatting");
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1);
|
||||
}
|
||||
CP_STATIC_CLASS(String);
|
||||
public:
|
||||
template<typename ... Args>
|
||||
static std::string Format(const std::string& format, Args... args)
|
||||
{
|
||||
int size = std::snprintf(nullptr, 0, format.c_str(), args...) + 1;
|
||||
CP_ASSERT(size > 0, "Format : Error during formatting");
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user