Fix fonts. Optimise vulkan renderer

This commit is contained in:
bailwillharr 2022-11-28 15:02:08 +00:00
parent d8911df619
commit 9c9b74f8fc
6 changed files with 102 additions and 83 deletions

View File

@ -22,7 +22,8 @@ public:
struct CharData {
glm::vec2 atlas_top_left{};
glm::vec2 atlas_bottom_right{};
glm::vec2 offset{};
glm::vec2 char_top_left{};
glm::vec2 char_bottom_right{};
float xAdvance{};
};

View File

@ -13,12 +13,13 @@ UI::UI(Object* parent) : Component(parent, TypeEnum::UI)
m_shader = parent->res.get<resources::Shader>("shaders/font.glsl");
m_atlasMesh = std::make_unique<resources::Mesh>(std::vector<Vertex>{
{ { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } },
{ { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } },
{ { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } },
{ { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } }
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
{ { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f } },
{ { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } },
{ { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
{ { 1.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 1.0f } },
});
}
@ -38,14 +39,15 @@ void UI::render(glm::mat4 transform, glm::mat4 view)
glm::vec2 size;
} pushConsts{};
int advance = 0;
float advance = 0.0f;
for (char c : m_text) {
auto charData = m_font->getCharData(c);
pushConsts.m = glm::mat4{1.0f};
charData.char_top_left.y *= -1;
pushConsts.m = transform;
pushConsts.atlas_top_left = charData.atlas_top_left;
pushConsts.atlas_bottom_right = charData.atlas_bottom_right;
pushConsts.offset = charData.offset;
pushConsts.size = (charData.char_bottom_right - charData.char_top_left);
pushConsts.offset = glm::vec2{ charData.char_top_left.x + advance, charData.char_top_left.y };
gfxdev->draw(
m_shader->getPipeline(), m_atlasMesh->vb, m_atlasMesh->ib, m_atlasMesh->m_indices.size(),
&pushConsts, sizeof(pushConsts), m_font->getAtlasTexture());

View File

@ -95,6 +95,7 @@ namespace engine {
};
struct DrawCall {
const gfx::Pipeline* pipeline = nullptr; // for performance, keep this the same for consecutive draw calls
const gfx::Buffer* vertexBuffer = nullptr;
const gfx::Buffer* indexBuffer = nullptr; // if this is nullptr, don't use indexed
uint32_t count = 0;
@ -1011,7 +1012,7 @@ namespace engine {
std::array<VkCommandBuffer, FRAMES_IN_FLIGHT> commandBuffers{};
std::array<VkFence, FRAMES_IN_FLIGHT> inFlightFences{};
std::map<const gfx::Pipeline*, std::queue<DrawCall>> drawQueues{};
std::queue<DrawCall> drawQueue{};
VkDescriptorSetLayoutBinding uboLayoutBinding{};
VkDescriptorSetLayout descriptorSetLayout{};
@ -1510,12 +1511,14 @@ namespace engine {
void GFXDevice::draw(const gfx::Pipeline* pipeline, const gfx::Buffer* vertexBuffer, const gfx::Buffer* indexBuffer, uint32_t count, const void* pushConstantData, size_t pushConstantSize, const gfx::Texture* texture)
{
assert(vertexBuffer->type == gfx::BufferType::VERTEX);
assert(pipeline != nullptr);
assert(vertexBuffer != nullptr);
assert(vertexBuffer->type == gfx::BufferType::VERTEX);
assert(indexBuffer == nullptr || indexBuffer->type == gfx::BufferType::INDEX);
assert(pushConstantSize <= PUSH_CONSTANT_MAX_SIZE);
DrawCall call{
.pipeline = pipeline,
.vertexBuffer = vertexBuffer,
.indexBuffer = indexBuffer, // will be ignored if nullptr
.count = count,
@ -1525,7 +1528,7 @@ namespace engine {
call.texture = texture; // will be ignored if nullptr
pimpl->drawQueues[pipeline].push(call);
pimpl->drawQueue.push(call);
}
@ -1570,7 +1573,7 @@ namespace engine {
renderPassInfo.renderArea.extent = pimpl->swapchain.extent;
std::array<VkClearValue, 2> clearValues{};
clearValues[0].color = { {0.1f, 0.1f, 0.8f, 1.0f} };
clearValues[0].color = { {0.0f, 0.0f, 0.0f, 1.0f} };
clearValues[1].depthStencil = { 1.0f, 0 };
renderPassInfo.clearValueCount = (uint32_t)clearValues.size();
renderPassInfo.pClearValues = clearValues.data();
@ -1595,33 +1598,50 @@ namespace engine {
VkDeviceSize offsets[] = { 0 };
for (auto& [pipeline, queue] : pimpl->drawQueues) {
vkCmdBindPipeline(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->handle);
vkCmdBindDescriptorSets(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 0, 1, &pipeline->descriptorSets[frameIndex], 0, nullptr);
while (queue.empty() == false) {
const gfx::Pipeline* lastPipeline = nullptr;
const gfx::Texture* lastTexture = nullptr;
const gfx::Buffer* lastVertexBuffer = nullptr;
const gfx::Buffer* lastIndexBuffer = nullptr;
while (pimpl->drawQueue.empty() == false) {
DrawCall call = queue.front();
DrawCall call = pimpl->drawQueue.front();
vkCmdBindDescriptorSets(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->layout, 1, 1, &call.texture->descriptorSets[frameIndex], 0, nullptr);
vkCmdPushConstants(pimpl->commandBuffers[frameIndex], pipeline->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, PUSH_CONSTANT_MAX_SIZE, call.pushConstantData);
vkCmdBindVertexBuffers(pimpl->commandBuffers[frameIndex], 0, 1, &call.vertexBuffer->buffer, offsets);
if (call.indexBuffer == nullptr) {
// no index buffer
vkCmdDraw(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0);
} else {
// use index buffer
vkCmdBindIndexBuffer(pimpl->commandBuffers[frameIndex], call.indexBuffer->buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0, 0);
}
queue.pop();
if (call.pipeline != lastPipeline) {
vkCmdBindPipeline(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, call.pipeline->handle);
// bind pipeline uniform-buffer
vkCmdBindDescriptorSets(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, call.pipeline->layout, 0, 1, &call.pipeline->descriptorSets[frameIndex], 0, nullptr);
}
}
pimpl->drawQueues.clear();
if (call.texture != lastTexture) {
// set the texture
vkCmdBindDescriptorSets(pimpl->commandBuffers[frameIndex], VK_PIPELINE_BIND_POINT_GRAPHICS, call.pipeline->layout, 1, 1, &call.texture->descriptorSets[frameIndex], 0, nullptr);
}
// like uniforms but faster
vkCmdPushConstants(pimpl->commandBuffers[frameIndex], call.pipeline->layout, VK_SHADER_STAGE_VERTEX_BIT, 0, PUSH_CONSTANT_MAX_SIZE, call.pushConstantData);
if (call.vertexBuffer != lastVertexBuffer) {
vkCmdBindVertexBuffers(pimpl->commandBuffers[frameIndex], 0, 1, &call.vertexBuffer->buffer, offsets);
}
if (call.indexBuffer == nullptr) {
// no index buffer
vkCmdDraw(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0);
} else {
// use index buffer
if (call.indexBuffer != lastIndexBuffer) {
vkCmdBindIndexBuffer(pimpl->commandBuffers[frameIndex], call.indexBuffer->buffer, 0, VK_INDEX_TYPE_UINT32);
}
vkCmdDrawIndexed(pimpl->commandBuffers[frameIndex], call.count, 1, 0, 0, 0);
}
lastPipeline = call.pipeline;
lastTexture = call.texture;
lastVertexBuffer = call.vertexBuffer;
lastIndexBuffer = call.indexBuffer;
pimpl->drawQueue.pop();
}
vkCmdEndRenderPass(pimpl->commandBuffers[frameIndex]);
@ -1783,7 +1803,7 @@ namespace engine {
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = attribDescs.size();
vertexInputInfo.vertexAttributeDescriptionCount = (uint32_t)attribDescs.size();
vertexInputInfo.pVertexAttributeDescriptions = attribDescs.data();
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
@ -1810,7 +1830,7 @@ namespace engine {
VkPipelineDynamicStateCreateInfo dynamicState{};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = dynamicStates.size();
dynamicState.dynamicStateCount = (uint32_t)dynamicStates.size();
dynamicState.pDynamicStates = dynamicStates.data();
VkPipelineViewportStateCreateInfo viewportState{};
@ -1898,7 +1918,7 @@ namespace engine {
VkPipelineLayoutCreateInfo layoutInfo{};
layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
layoutInfo.setLayoutCount = setLayouts.size();
layoutInfo.setLayoutCount = (uint32_t)setLayouts.size();
layoutInfo.pSetLayouts = setLayouts.data();
layoutInfo.pushConstantRangeCount = 1;
layoutInfo.pPushConstantRanges = &pushConstantRange;

View File

@ -19,32 +19,35 @@ Font::Font(const std::filesystem::path& resPath) : Resource(resPath, "font")
constexpr int FIRST_CHAR = 32;
constexpr int NUM_CHARS = 96;
constexpr float SCALE = 128.0f;
constexpr int BITMAP_WIDTH = 1024;
constexpr int BITMAP_HEIGHT = 1024;
auto pixels = std::make_unique<unsigned char[]>(BITMAP_WIDTH * BITMAP_HEIGHT);
auto bakedChars = std::make_unique<stbtt_bakedchar[]>(NUM_CHARS);
stbtt_BakeFontBitmap(fontBuffer->data(), 0, 128.0f, pixels.get(), BITMAP_WIDTH, BITMAP_HEIGHT, FIRST_CHAR, NUM_CHARS, bakedChars.get());
stbtt_BakeFontBitmap(fontBuffer->data(), 0, SCALE, pixels.get(), BITMAP_WIDTH, BITMAP_HEIGHT, FIRST_CHAR, NUM_CHARS, bakedChars.get());
auto textureData = std::make_unique<uint8_t[]>(BITMAP_WIDTH * BITMAP_HEIGHT * 4);
for (int i = 0; i < BITMAP_WIDTH * BITMAP_HEIGHT; i++) {
textureData[i * 4 + 0] = pixels[i];
textureData[i * 4 + 1] = pixels[i];
textureData[i * 4 + 2] = pixels[i];
textureData[i * 4 + 0] = 255;
textureData[i * 4 + 1] = 255;
textureData[i * 4 + 2] = 255;
textureData[i * 4 + 3] = pixels[i];
}
m_atlas = gfxdev->createTexture(textureData.get(), BITMAP_WIDTH, BITMAP_HEIGHT, gfx::TextureFilter::LINEAR, gfx::TextureFilter::LINEAR);
for (int i = FIRST_CHAR; i < NUM_CHARS; i++) {
for (int i = FIRST_CHAR; i < FIRST_CHAR + NUM_CHARS; i++) {
CharData charData{};
charData.atlas_top_left = { bakedChars[i].x0, bakedChars[i].y0 };
charData.atlas_bottom_right = { bakedChars[i].x1, bakedChars[i].y1 };
charData.offset = { bakedChars[i].xoff, bakedChars[i].yoff };
charData.xAdvance = bakedChars[i].xadvance;
stbtt_bakedchar baked = bakedChars[i - FIRST_CHAR];
charData.atlas_top_left = { (float)baked.x0 / (float)BITMAP_WIDTH, (float)baked.y0 / (float)BITMAP_HEIGHT };
charData.atlas_bottom_right = { (float)baked.x1 / (float)BITMAP_WIDTH, (float)baked.y1 / (float)BITMAP_HEIGHT};
charData.char_top_left = { baked.xoff, baked.yoff };
charData.char_bottom_right = charData.char_top_left + glm::vec2{ baked.x1 - baked.x0, baked.y1 - baked.y0 };
charData.xAdvance = baked.xadvance;
m_charData[i] = charData;
// TODO
}
}

View File

@ -2,6 +2,8 @@
layout( push_constant ) uniform Constants {
mat4 model;
vec2 atlas_top_left;
vec2 atlas_bottom_right;
vec2 offset;
vec2 size;
} constants;
@ -13,6 +15,8 @@ layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
gl_Position = constants.model * vec4(inPosition, 1.0);
fragUV = inUV;
vec2 position = inPosition.xy * constants.size + constants.offset;
position *= 0.001;
gl_Position = constants.model * vec4(position, 0.0, 1.0);
fragUV = constants.atlas_top_left + (inUV * (constants.atlas_bottom_right - constants.atlas_top_left));
}

View File

@ -58,8 +58,6 @@ void playGame()
auto camCamera = cam->createComponent<engine::components::Camera>();
camCamera->usePerspective(130.0f);
cam->createComponent<CameraController>();
cam->createComponent<engine::components::Renderer>()->m_mesh = genSphereMesh(0.2f, 20);
cam->getComponent<engine::components::Renderer>()->setTexture("textures/cobble_stone.png");
/*
auto gun = cam->createChild("gun");
@ -73,8 +71,6 @@ void playGame()
*/
// FLOOR
/*
constexpr float GRASS_DENSITY = 128.0f * 20.0f;
auto floor = app.scene()->createChild("floor");
auto floorRenderer = floor->createComponent<engine::components::Renderer>();
@ -89,15 +85,12 @@ void playGame()
{ { -16.0f, 0.0f, 16.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, GRASS_DENSITY } }
});
floor->transform.scale = { 100.0f, 1.0f, 100.0f };
*/
/*
auto cube = app.scene()->createChild("cube");
auto cubeRen = cube->createComponent<engine::components::Renderer>();
cubeRen->setMesh("meshes/cube.mesh");
cube->transform.position = glm::vec3{ -5.0f, 1.0f, 0.0f };
class Spin : public engine::components::CustomComponent {
public:
Spin(engine::Object* parent) : CustomComponent(parent)
{
@ -123,32 +116,34 @@ void playGame()
pitchQuat.w = glm::cos(halfPitch);
parent.transform.rotation *= pitchQuat;
}
private:
float m_yaw = 0.0f;
};
app.scene()->getChild("cube")->createComponent<Spin>();
*/
/*auto sphere = app.scene()->createChild("sphere");
sphere->transform.position = { 10.0f, 5.0f, 10.0f };
*/
/*auto sphereRenderer = sphere->createComponent<engine::components::Renderer>();
sphereRenderer->m_mesh = genSphereMesh(5.0f, 100, false);
sphereRenderer->setTexture("textures/cobble_stone.png");
cube->createComponent<Spin>();
// boundary
auto bounds = app.scene()->createChild("bounds");
auto boundsRen = bounds->createComponent<engine::components::Renderer>();
boundsRen->m_mesh = genSphereMesh(100.0f, 36, true);
boundsRen->setTexture("textures/metal.jpg");
*/
auto message = app.scene()->createChild("message");
message->transform.position = { 0.0f, 2.0f, 0.0f };
message->transform.position = { -1.0f, 0.95f, 0.0f };
message->transform.scale *= 0.5f;
auto messageUI = message->createComponent<engine::components::UI>();
class FPSTextUpdater : public engine::components::CustomComponent {
engine::components::UI* textUI = nullptr;
public:
FPSTextUpdater(engine::Object* parent) : CustomComponent(parent)
{
textUI = parent->getComponent<engine::components::UI>();
}
void onUpdate(glm::mat4 t) override
{
textUI->m_text = std::to_string(parent.win.dt() * 1000.0f) + " ms";
}
};
message->createComponent<FPSTextUpdater>();
/*
auto myModel = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/pyramid/pyramid.dae").string());
@ -156,17 +151,11 @@ void playGame()
auto myRoom = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/room/room.dae").string());
myRoom->transform.position = { 9.0f, 0.1f, 3.0f };
*/
auto astronaut = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/astronaut/astronaut.dae").string());
astronaut->transform.position.z += 5.0f;
astronaut->createComponent<Spin>();
auto plane = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/plane/plane.dae").string());
plane->transform.position = { -30.0f, 2.0f, 10.0f };
*/
auto van = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/van/van.dae").string());
/*
auto lego = engine::util::loadAssimpMeshFromFile(app.scene(), app.resources()->getFilePath("models/lego/lego.dae").string());
lego->transform.position = { -30.0f, -33.0f, -30.0f };