Not even with long texts and small scales

This commit is contained in:
Dynamitos
2022-04-17 09:10:20 +02:00
parent 03e1a5784d
commit 796271f334
17 changed files with 127 additions and 105 deletions
+19 -16
View File
@@ -1,48 +1,51 @@
struct GlyphData
{
float2 bearing;
float2 size;
float4 bearingSize;
};
struct ViewData
{
float4x4 projectionMatrix;
}
struct TextData
{
float4 textColor;
float scale;
}
layout(set = 0, binding = 0)
ConstantBuffer<ViewData> viewData;
layout(set = 0, binding = 1)
SamplerState glyphSampler;
//layout(set = 1)
//StructuredBuffer<GlyphData> glyphData;
layout(set = 1)
RWStructuredBuffer<GlyphData> glyphData;
layout(set = 2)
Texture2D<uint> glyphTextures[];
layout(push_constant)
ConstantBuffer<float> scale;
ConstantBuffer<TextData> textData;
struct VertexStageInput
{
uint glyphIndex;
float2 position;
float2 widthHeight;
uint glyphIndex;
uint vertexId : SV_VertexID;
};
struct VertexStageOutput
{
float4 position : SV_Position;
float2 uvCoords : TEXCOORD;
float2 texCoords : TEXCOORD;
uint glyphIndex : GLYPHINDEX;
};
[shader("vertex")]
VertexStageOutput vertexMain(VertexStageInput input)
{
GlyphData glyph = glyphData[input.glyphIndex];
float xpos = input.position.x;
float ypos = input.position.y;
float xpos = input.position.x + glyph.bearing.x * scale;
float ypos = input.position.y - (glyph.size.y - glyph.bearing.y) * scale;
float w = glyph.size.x * scale;
float h = glyph.size.y * scale;
float w = input.widthHeight.x;
float h = input.widthHeight.y;
float4 coordinates[4] = {
float4(xpos, ypos, 0, 1),
@@ -52,7 +55,7 @@ VertexStageOutput vertexMain(VertexStageInput input)
};
float4 vertex = coordinates[input.vertexId];
VertexStageOutput output;
output.uvCoords = vertex.zw;
output.texCoords = vertex.zw;
output.position = mul(viewData.projectionMatrix, float4(vertex.xy, 0, 1));
output.glyphIndex = input.glyphIndex;
return output;
@@ -61,9 +64,9 @@ VertexStageOutput vertexMain(VertexStageInput input)
[shader("fragment")]
float4 fragmentMain(
float4 position : SV_Position,
float2 uvCoords : TEXCOORD,
float2 texCoords : TEXCOORD,
uint glyphIndex : GLYPHINDEX
) : SV_Target
{
return glyphTextures[glyphIndex].Sample(glyphSampler, uvCoords);
return textData.textColor * glyphTextures[glyphIndex].Sample(glyphSampler, texCoords);
}
+9 -3
View File
@@ -37,11 +37,13 @@ uint8 transparentPixel = 0;
void FontAsset::load()
{
FT_Library ft;
assert(!FT_Init_FreeType(&ft));
FT_Error error = FT_Init_FreeType(&ft);
assert(!error);
FT_Face face;
assert(!FT_New_Face(ft, getFullPath().c_str(), 0, &face));
error = FT_New_Face(ft, getFullPath().c_str(), 0, &face);
assert(!error);
FT_Set_Pixel_Sizes(face, 0, 48);
for(uint8 c = 0; c < 128; ++c)
for(uint32 c = 0; c < 256; ++c)
{
Gfx::PGraphics graphics = WindowManager::getGraphics();
if(FT_Load_Char(face, c, FT_LOAD_RENDER))
@@ -61,6 +63,10 @@ void FontAsset::load()
imageData.resourceData.size = imageData.width * imageData.height;
if(imageData.width == 0 || imageData.width == 0)
{
glyph.size.x = 1;
glyph.size.y = 1;
glyph.bearing.x = 0;
glyph.bearing.y = 0;
imageData.width = 1;
imageData.height = 1;
imageData.resourceData.size = sizeof(uint8);
+2 -2
View File
@@ -21,9 +21,9 @@ public:
IVector2 bearing;
uint32 advance;
};
const Map<uint32, Glyph> getGlyphData() const { return glyphs; }
const std::map<uint32, Glyph> getGlyphData() const { return glyphs; }
private:
Map<uint32, Glyph> glyphs;
std::map<uint32, Glyph> glyphs;
};
DECLARE_REF(FontAsset)
} // namespace Seele
@@ -199,6 +199,10 @@ StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, co
, contents(resourceData.size)
, stride(stride)
{
if(resourceData.data != nullptr)
{
std::memcpy(contents.data(), resourceData.data, resourceData.size);
}
}
StructuredBuffer::~StructuredBuffer()
{
+49 -44
View File
@@ -27,23 +27,38 @@ void TextPass::beginFrame()
float y = render.position.y;
for(uint32 c : render.text)
{
const GlyphData& glyph = fontData.glyphDataSet[fontData.characterToGlyphIndex[c]];
Vector2 bearing = glyph.bearing;
Vector2 size = glyph.size;
float xpos = x + bearing.x * render.scale;
float ypos = y - (size.y - bearing.y) * render.scale;
float w = size.x * render.scale;
float h = size.y * render.scale;
instanceData.add(GlyphInstanceData{
.position = Vector2(xpos, ypos),
.widthHeight = Vector2(w, h),
.glyphIndex = fontData.characterToGlyphIndex[c],
.position = Vector2(x, y)
});
x += (fontData.characterAdvance[c] >> 6) * render.scale;
x += (glyph.advance >> 6) * render.scale;
}
VertexBufferCreateInfo vbInfo;
vbInfo.numVertices = static_cast<uint32>(instanceData.size());
vbInfo.vertexSize = sizeof(GlyphInstanceData);
vbInfo.resourceData.data = reinterpret_cast<uint8*>(instanceData.data());
vbInfo.resourceData.size = static_cast<uint32>(instanceData.size() * sizeof(GlyphInstanceData));
VertexBufferCreateInfo vbInfo = {
.resourceData = {
.size = static_cast<uint32>(instanceData.size() * sizeof(GlyphInstanceData)),
.data = reinterpret_cast<uint8*>(instanceData.data()),
},
.vertexSize = sizeof(GlyphInstanceData),
.numVertices = static_cast<uint32>(instanceData.size()),
};
resources.vertexBuffer = graphics->createVertexBuffer(vbInfo);
resources.glyphDataSet = fontData.glyphDataSet;
resources.textureArraySet = fontData.textureArraySet;
resources.scale = render.scale;
resources.textData = {
.textColor = render.textColor,
.scale = render.scale,
};
}
//co_return;
}
@@ -57,10 +72,10 @@ void TextPass::render()
Gfx::PRenderCommand command = graphics->createRenderCommand("TextPassCommand");
command->setViewport(viewport);
command->bindPipeline(pipeline);
command->bindDescriptor({generalSet, resources.glyphDataSet, resources.textureArraySet});
command->bindDescriptor({generalSet, resources.textureArraySet});
command->bindVertexBuffer({VertexInputStream(0, 0, resources.vertexBuffer)});
command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float), &resources.scale);
command->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(TextData), &resources.textData);
command->draw(4, static_cast<uint32>(resources.vertexBuffer->getNumVertices()), 0, 0);
commands.add(command);
}
@@ -101,36 +116,39 @@ void TextPass::createRenderPass()
Array<Gfx::VertexElement> elements;
elements.add({
.streamIndex = 0,
.offset = offsetof(GlyphInstanceData, glyphIndex),
.vertexFormat = Gfx::SE_FORMAT_R32_UINT,
.offset = offsetof(GlyphInstanceData, position),
.vertexFormat = Gfx::SE_FORMAT_R32G32_SFLOAT,
.attributeIndex = 0,
.stride = sizeof(GlyphInstanceData),
.bInstanced = 1
});
elements.add({
.streamIndex = 0,
.offset = offsetof(GlyphInstanceData, position),
.offset = offsetof(GlyphInstanceData, widthHeight),
.vertexFormat = Gfx::SE_FORMAT_R32G32_SFLOAT,
.attributeIndex = 1,
.stride = sizeof(GlyphInstanceData),
.bInstanced = 1
});
elements.add({
.streamIndex = 0,
.offset = offsetof(GlyphInstanceData, glyphIndex),
.vertexFormat = Gfx::SE_FORMAT_R32_UINT,
.attributeIndex = 2,
.stride = sizeof(GlyphInstanceData),
.bInstanced = 1
});
declaration = graphics->createVertexDeclaration(elements);
generalLayout = graphics->createDescriptorLayout("TextGeneral");
generalLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
generalLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER);
generalLayout->create();
glyphDataLayout = graphics->createDescriptorLayout("TextGlyphData");
glyphDataLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
glyphDataLayout->create();
textureArrayLayout = graphics->createDescriptorLayout("TextTextureArray");
textureArrayLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT);
textureArrayLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 256, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT);
textureArrayLayout->create();
Matrix4 projectionMatrix = glm::ortho(0.f, (float)viewport->getSizeX(), 0.f, (float)viewport->getSizeY());
projectionBuffer = graphics->createUniformBuffer({
.resourceData = {
@@ -154,12 +172,11 @@ void TextPass::createRenderPass()
pipelineLayout = graphics->createPipelineLayout();
pipelineLayout->addDescriptorLayout(0, generalLayout);
pipelineLayout->addDescriptorLayout(1, glyphDataLayout);
pipelineLayout->addDescriptorLayout(2, textureArrayLayout);
pipelineLayout->addDescriptorLayout(1, textureArrayLayout);
pipelineLayout->addPushConstants({
.stageFlags = Gfx::SE_SHADER_STAGE_VERTEX_BIT,
.stageFlags = Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0,
.size = sizeof(float)});
.size = sizeof(TextData)});
pipelineLayout->create();
Gfx::PRenderTargetLayout layout = new Gfx::RenderTargetLayout(renderTarget, depthAttachment);
@@ -190,34 +207,22 @@ TextPass::FontData& TextPass::getFontData(PFontAsset font)
if(fontData.exists(font))
{
return fontData[font];
}
const Map<uint32, FontAsset::Glyph>& fontGlyphs = font->getGlyphData();
}
const auto& fontGlyphs = font->getGlyphData();
FontData& fd = fontData[font];
Array<GlyphData> buffer;
Array<GlyphData> glyphData;
Array<Gfx::PTexture> textures;
buffer.reserve(fontGlyphs.size());
glyphData.reserve(fontGlyphs.size());
for(const auto& [key, value] : fontGlyphs)
{
fd.characterToGlyphIndex[key] = static_cast<uint32>(buffer.size());
fd.characterAdvance[key] = value.advance;
GlyphData& gd = buffer.add();
fd.characterToGlyphIndex[key] = static_cast<uint32>(glyphData.size());
GlyphData& gd = glyphData.add();
gd.bearing = value.bearing;
gd.size = value.size;
gd.advance = value.advance;
textures.add(value.texture);
}
StructuredBufferCreateInfo bufferInfo = {
.resourceData = {
.size = static_cast<uint32>(buffer.size() * sizeof(GlyphData)),
.data = reinterpret_cast<uint8*>(buffer.data()),
},
.stride = sizeof(GlyphData),
.bDynamic = false,
};
Gfx::PStructuredBuffer glyphBuffer = graphics->createStructuredBuffer(bufferInfo);
fd.glyphDataSet = glyphDataLayout->allocateDescriptorSet();
fd.glyphDataSet->updateBuffer(0, glyphBuffer);
fd.glyphDataSet->writeChanges();
fd.glyphDataSet = glyphData;
fd.textureArraySet = textureArrayLayout->allocateDescriptorSet();
fd.textureArraySet->updateTextureArray(0, textures);
+10 -9
View File
@@ -37,21 +37,24 @@ private:
{
Vector2 bearing;
Vector2 size;
uint32 advance;
};
struct GlyphInstanceData
{
uint32 glyphIndex;
Vector2 position;
Vector2 widthHeight;
uint32 glyphIndex;
};
struct TextData
{
Vector4 textColor;
float scale;
};
struct FontData
{
Gfx::PDescriptorSet glyphDataSet;
Gfx::PDescriptorSet textureArraySet;
Array<GlyphData> glyphDataSet;
Map<uint32, uint32> characterToGlyphIndex;
// Logically this should be part of GlyphData,
// but because GlyphData mirrors shader data and we need
// the advance on the CPU, we need this in a separate structure
Map<uint32, uint32> characterAdvance;
};
FontData& getFontData(PFontAsset font);
Map<PFontAsset, FontData> fontData;
@@ -59,9 +62,8 @@ private:
struct TextResources
{
Gfx::PVertexBuffer vertexBuffer;
Gfx::PDescriptorSet glyphDataSet;
Gfx::PDescriptorSet textureArraySet;
float scale;
TextData textData;
};
Array<TextResources> textResources;
@@ -70,7 +72,6 @@ private:
Gfx::PTexture2D depthBuffer;
Gfx::PDescriptorLayout generalLayout;
Gfx::PDescriptorLayout glyphDataLayout;
Gfx::PDescriptorLayout textureArrayLayout;
Gfx::PDescriptorSet generalSet;
+11 -4
View File
@@ -90,16 +90,18 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice
return nullptr;
}
}
for (auto& [allocatedOffset, freeAllocation] : freeRanges)
for (auto& it : freeRanges)
{
VkDeviceSize allocatedOffset = it.first;
PSubAllocation freeAllocation = it.second;
assert(allocatedOffset == freeAllocation->allocatedOffset);
VkDeviceSize alignedOffset = align(allocatedOffset, alignment);
VkDeviceSize alignmentAdjustment = alignedOffset - allocatedOffset;
VkDeviceSize size = alignmentAdjustment + requestedSize;
if (freeAllocation->size == size)
{
freeRanges.erase(allocatedOffset);
activeAllocations[allocatedOffset] = freeAllocation.getHandle();
freeRanges.erase(allocatedOffset);
bytesUsed += size;
return freeAllocation;
}
@@ -184,7 +186,10 @@ void Allocation::markFree(SubAllocation *allocation)
activeAllocations.erase(allocation->allocatedOffset);
}
bytesUsed -= allocation->allocatedSize;
// TODO: delete allocation when bytesUsed == 0
if(bytesUsed == 0)
{
allocator->free(this);
}
}
Allocator::Allocator(PGraphics graphics)
@@ -230,6 +235,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2
{
PAllocation newAllocation = new Allocation(graphics, this, requirements.size, memoryTypeIndex, properties, dedicatedInfo);
heaps[heapIndex].allocations.add(newAllocation);
heaps[heapIndex].inUse += newAllocation->bytesAllocated;
return newAllocation->getSuballocation(requirements.size, requirements.alignment);
}
}
@@ -245,6 +251,7 @@ PSubAllocation Allocator::allocate(const VkMemoryRequirements2 &memRequirements2
// no suitable allocations found, allocate new block
PAllocation newAllocation = new Allocation(graphics, this, (requirements.size > MemoryBlockSize) ? requirements.size : (VkDeviceSize)MemoryBlockSize, memoryTypeIndex, properties, nullptr);
heaps[heapIndex].allocations.add(newAllocation);
heaps[heapIndex].inUse += newAllocation->bytesAllocated;
return newAllocation->getSuballocation(requirements.size, requirements.alignment);
}
@@ -257,13 +264,13 @@ void Allocator::free(Allocation *allocation)
{
if (heap.allocations[i] == allocation)
{
heap.inUse -= allocation->bytesAllocated;
heap.allocations.removeAt(i, false);
return;
}
}
}
}
VkResult Allocator::findMemoryType(uint32 typeBits, VkMemoryPropertyFlags properties, uint8 *typeIndex)
{
for (uint8 memoryIndex = 0; memoryIndex < memProperties.memoryTypeCount && typeBits; ++memoryIndex)
+2 -1
View File
@@ -142,7 +142,7 @@ public:
}
void free(Allocation *allocation);
void notifyUsageChanged(int64 usageChange);
private:
enum
{
@@ -151,6 +151,7 @@ private:
struct HeapInfo
{
VkDeviceSize maxSize = 0;
VkDeviceSize inUse = 0;
Array<PAllocation> allocations;
};
Array<HeapInfo> heaps;
+3 -4
View File
@@ -14,7 +14,7 @@ struct PendingBuffer
bool bWriteOnly;
};
static Map<ShaderBuffer *, PendingBuffer> pendingBuffers;
static std::map<ShaderBuffer *, PendingBuffer> pendingBuffers;
ShaderBuffer::ShaderBuffer(PGraphics graphics, uint32 size, VkBufferUsageFlags usage, Gfx::QueueType& queueType, bool bDynamic)
: graphics(graphics)
@@ -54,8 +54,7 @@ ShaderBuffer::ShaderBuffer(PGraphics graphics, uint32 size, VkBufferUsageFlags u
VK_CHECK(vkCreateBuffer(graphics->getDevice(), &info, nullptr, &buffers[i].buffer));
bufferReqInfo.buffer = buffers[i].buffer;
vkGetBufferMemoryRequirements2(graphics->getDevice(), &bufferReqInfo, &memRequirements);
auto temp = graphics->getAllocator()->allocate(memRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buffers[i].buffer);
buffers[i].allocation = temp;
buffers[i].allocation = graphics->getAllocator()->allocate(memRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, buffers[i].buffer);
vkBindBufferMemory(graphics->getDevice(), buffers[i].buffer, buffers[i].allocation->getHandle(), buffers[i].allocation->getOffset());
}
}
@@ -245,7 +244,7 @@ void ShaderBuffer::unlock()
auto found = pendingBuffers.find(this);
if (found != pendingBuffers.end())
{
PendingBuffer pending = found->value;
PendingBuffer pending = found->second;
pending.stagingBuffer->flushMappedMemory();
pendingBuffers.erase(this);
if (pending.bWriteOnly)
@@ -229,10 +229,6 @@ void Window::present()
while (presentResult != VK_SUCCESS)
{
presentResult = vkQueuePresentKHR(graphics->getGraphicsCommands()->getQueue()->getHandle(), &info);
if(presentResult == VK_ERROR_OUT_OF_DATE_KHR)
{
recreateSwapchain(windowState);
}
}
Gfx::currentFrameIndex = (Gfx::currentFrameIndex + 1)%Gfx::numFramesBuffered;
static double lastFrameTime = 0.f;
-1
View File
@@ -11,7 +11,6 @@ CameraActor::CameraActor()
cameraComponent = new CameraComponent();
cameraComponent->fieldOfView = 70.0f;
cameraComponent->aspectRatio = 1.777778f;
cameraComponent->setParent(sceneComponent);
cameraComponent->setOwner(this);
sceneComponent->addChildComponent(cameraComponent);
@@ -53,6 +53,14 @@ void CameraComponent::moveY(float amount)
bNeedsViewBuild = true;
}
void CameraComponent::setViewport(Gfx::PViewport newViewport)
{
viewport = newViewport;
aspectRatio = viewport->getSizeX() / (float)viewport->getSizeY();
bNeedsProjectionBuild = true;
}
void CameraComponent::buildViewMatrix()
{
Vector eyePos = getAbsoluteTransform().getPosition();
@@ -1,6 +1,7 @@
#pragma once
#include "Component.h"
#include "Math/Matrix.h"
#include "Graphics/GraphicsResources.h"
namespace Seele
{
@@ -30,6 +31,7 @@ public:
{
return getTransform().getPosition();
}
void setViewport(Gfx::PViewport viewport);
void mouseMove(float deltaX, float deltaY);
void mouseScroll(float x);
void moveX(float amount);
@@ -42,6 +44,8 @@ private:
void buildViewMatrix();
void buildProjectionMatrix();
Gfx::PViewport viewport;
//Transforms relative to actor
Matrix4 viewMatrix;
Matrix4 projectionMatrix;
-9
View File
@@ -27,20 +27,11 @@ public:
void addChildComponent(PComponent component);
virtual void notifySceneAttach(PScene scene);
//void setAbsoluteLocation(Vector location);
//void setAbsoluteRotation(Vector rotation);
//void setAbsoluteRotation(Quaternion rotation);
//void setWorldScale(Vector scale);
void setRelativeLocation(Vector location);
void setRelativeRotation(Vector rotation);
void setRelativeRotation(Quaternion rotation);
void setRelativeScale(Vector scale);
//void addAbsoluteTranslation(Vector translation);
//void addAbsoluteRotation(Vector rotation);
//void addAbsoluteRotation(Quaternion rotation);
void addRelativeLocation(Vector translation);
void addRelativeRotation(Vector rotation);
void addRelativeRotation(Quaternion rotation);
+5 -4
View File
@@ -21,10 +21,11 @@ InspectorView::InspectorView(Gfx::PGraphics graphics, PWindow window, const View
textPass.createRenderPass();
TextRender& render = textPassData.texts.add();
render.font = AssetRegistry::findFont("Calibri");
render.text = "Seele Engine";
render.position = Vector2(200.f, 300.f);
render.scale = 1.0f;
render.textColor = Vector4(1, 1, 1, 1);
render.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis magna ex. Morbi ullamcorper fringilla risus eget vehicula. Praesent vel quam vel ante molestie gravida vitae ac enim. Donec vitae eleifend orci. Phasellus at sodales lorem, ac eleifend turpis. Vivamus vitae condimentum lacus, a bibendum neque. Ut et est ut felis varius vehicula. Etiam lorem magna, dapibus vitae felis in, vulputate suscipit neque. Aenean facilisis ac risus et scelerisque. Ut tincidunt eros quis posuere iaculis. Curabitur justo lacus, molestie id varius vel, sodales efficitur diam. Integer orci velit, condimentum sit amet turpis sit amet, congue blandit nisl. Donec pretium ligula id mauris pretium commodo. Mauris quis lectus mi. In blandit, dolor non accumsan venenatis, ipsum erat congue neque, quis elementum orci nunc vel justo. ";
//render.text = "Seele Engine";
render.position = Vector2(0.f, 300.f);
render.scale = 0.1f;
render.textColor = Vector4(1, 0, 0, 1);
}
InspectorView::~InspectorView()
+1
View File
@@ -18,6 +18,7 @@ Seele::SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const Viewpo
, lightCullingPass(LightCullingPass(graphics, viewport, activeCamera))
, basePass(BasePass(graphics, viewport, activeCamera))
{
activeCamera->getCameraComponent()->setViewport(viewport);
scene = new Scene(graphics);
scene->addActor(activeCamera);
AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Diffuse.png");
-4
View File
@@ -36,10 +36,6 @@ void Window::render()
view->render();
}
gfxHandle->endFrame();
if(owner->isActive())
{
render();
}
}
//co_return;
}