Cogs.Core
RenderMesh.cpp
1#include "RenderMesh.h"
2#include "RenderEffect.h"
3
4#include "Rendering/IGraphicsDevice.h"
5#include "Rendering/IContext.h"
6#include "Rendering/IBuffers.h"
7#include "Rendering/ICapabilities.h"
8#include "Rendering/VertexFormat.h"
9
10#include "Resources/VertexFormats.h"
11#include "Resources/Mesh.h"
12#include "Resources/Buffer.h"
13
14#include "Foundation/Logging/Logger.h"
15
16#include "Renderer.h"
17
18namespace
19{
20 using namespace Cogs::Core;
21
22 Cogs::Logging::Log logger = Cogs::Logging::getLogger("RenderMesh");
23
24
25 Cogs::BufferHandle updateStream(Cogs::IBuffers* buffers, Mesh* mesh, Cogs::Core::DataStream& stream, Cogs::BindFlags::EBindFlags bindflags, bool doSet)
26 {
27 // Note: Here the stream more or less owns the buffer, this won't work
28 // if buffers are shared across streams. But then we need something else
29 // like a RenderBufferManager to manage lifetime. But for now, it looks
30 // like there is always only one stream per buffer
31
32 // It is BufferManager that actually determines whether this is resident or not, which doesn't mean
33 // much when we update buffers here. So we don't trust or update the resident flag here and just
34 // check if the buffer exist.
36
37 if (Cogs::BufferHandle handle = Cogs::BufferHandle(intptr_t(buffer->getAttachedResource())); handle) {
38 buffers->releaseBuffer(handle);
39 buffer->unsetFlag(ResourceFlags::Resident);
40 buffer->attachResource(nullptr);
41 }
42
43 if (doSet && !buffer->empty()) {
44 Cogs::BufferHandle handle = buffers->loadBuffer((const uint8_t*)buffer->data(), buffer->size(), Cogs::Usage::Static, Cogs::AccessMode::None, bindflags, stream.stride);
45 if (Cogs::StringView name = mesh->getName(); !name.empty()) {
46 buffers->annotate(handle, name);
47 }
48 else {
49 buffers->annotate(handle, "RenderMesh");
50 }
51 buffer->setResident();
52 buffer->attachResource((RenderResource*)(intptr_t)handle.handle);
53 return handle;
54 }
55
57 }
58
59}
60
61
62Cogs::Core::RenderMesh::RenderMesh()
63{
64 type = RenderResourceType::RenderMesh;
65
66 for (size_t i = 0; i < MeshStreamsLayout::maxStreams; ++i) {
68 vertexBuffers[i] = VertexBufferHandle::NoHandle;
69 vertexOffsets[i] = 0;
70 vertexStrides[i] = 0;
71 }
72}
73
74
75Cogs::VertexArrayObjectHandle Cogs::Core::RenderMesh::getVertexArrayObject(IGraphicsDevice* device, const RenderEffect* renderEffect) const
76{
77 Cogs::IBuffers* buffers = device->getBuffers();
78 if (!renderEffect || !HandleIsValid(renderEffect->effectHandle)) {
79 LOG_ERROR(logger, "Trying to get a VAO for an invalid effect");
81 }
82
83 RenderResource::Id effectId = renderEffect->getIdentity();
84 if (auto it = vaos.find(effectId); it != vaos.end()) {
85 return it->second;
86 }
87
88 std::array<const VertexFormat*, MeshStreamsLayout::maxStreams> formats;
89 for (size_t i = 0; i < streamsLayout.numStreams; i++) {
90 formats[i] = Cogs::VertexFormats::getVertexFormat(streamsLayout.vertexFormats[i]);
91 }
92
93 Cogs::VertexArrayObjectHandle vao = buffers->loadVertexArrayObject(renderEffect->effectHandle,
94 vertexBuffers, streamsLayout.numStreams, formats.data(), vertexStrides, vertexOffsets,
95 indexBuffer, indexStride);
96 vaos.insert(std::make_pair(effectId, vao));
97 return vao;
98}
99
100
101Cogs::Core::ActivationResult Cogs::Core::RenderMesh::update(Mesh * mesh, IGraphicsDevice * device, RenderResources * /*resources*/)
102{
103 bool changed = false;
104 auto buffers = device->getBuffers();
105 bool supportUint32Indices = device->getCapabilities()->getDeviceCapabilities().UnsignedIntIndexes;
106
108 streamsLayout.numStreams = 0;
109 numVertexes = mesh->getCount();
110
111 for (size_t i = 0; i < VertexDataType::LastVertexType; ++i) {
113
114 if (mesh->hasStream(type)) {
115 Cogs::Core::DataStream& stream = mesh->getStream(type);
117 if (mesh->streamsUpdated & uint16_t(1 << i)) {
118 handle = updateStream(buffers, mesh, stream, Cogs::BindFlags::VertexBuffer, true);
119 }
120 else /*if (stream.buffer->isResident())*/ {
121 // See note above, we cannot trust isResident and just check if the resource exist.
122 handle = Cogs::BufferHandle(intptr_t(stream.buffer->getAttachedResource()));
123 }
124
125 if (HandleIsValid(handle)) {
126 vertexBuffers[streamsLayout.numStreams] = handle;
127 vertexOffsets[streamsLayout.numStreams] = stream.offset;
128 vertexStrides[streamsLayout.numStreams] = stream.stride;
129 streamsLayout.vertexFormats[streamsLayout.numStreams] = stream.format;
130 streamsLayout.numStreams++;
131 }
132 }
133 }
134
135 mesh->streamsUpdated = 0;
137 changed = true;
138 }
139
141 if (mesh->hasStream(VertexDataType::Indexes)) {
142 DataStream& stream = mesh->getStream(VertexDataType::Indexes);
143 if (!supportUint32Indices && indexStride == 4) {
144 LOG_ERROR_ONCE(logger, "Mesh indices are uint32 which is not supported by graphics device");
145 indexBuffer = IndexBufferHandle::NoHandle;
146 }
147 else {
148 indexBuffer = updateStream(buffers, mesh, stream, Cogs::BindFlags::IndexBuffer, mesh->isIndexed());
149 indexOffset = stream.offset;
150 indexStride = stream.stride;
151 }
152 }
153 else {
154 indexBuffer = IndexBufferHandle::NoHandle;
155 }
157 changed = true;
158 }
159
160 if (changed) {
161 streamsLayout.updateHash();
162
163 for (auto& it : vaos) {
164 buffers->releaseVertexArrayObject(it.second);
165 }
166 vaos.clear();
167 }
168
169 numVertexes = mesh->getCount();
170
171 setActive();
172
174}
175
176void Cogs::Core::RenderMesh::release(Renderer * renderer)
177{
178 Cogs::IBuffers* buffers = renderer->getDevice()->getBuffers();
179
180 for (auto& it : vaos) {
181 buffers->releaseVertexArrayObject(it.second);
182 }
183 vaos.clear();
184
185 setReleased();
186}
Contains render resources used by the renderer.
Core renderer system.
Definition: Renderer.h:28
IGraphicsDevice * getDevice() override
Get the graphics device used by the renderer.
Definition: Renderer.h:45
Represents a graphics device used to manage graphics resources and issue drawing commands.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
virtual IBuffers * getBuffers()=0
Get a pointer to the buffer management interface.
Log implementation class.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:148
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
ActivationResult
Defines results for resource activation.
Definition: ResourceBase.h:14
@ Success
Resource activated successfully.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:181
@ None
The buffer can not be either read from or written to by the CPU after creation.
Definition: Flags.h:46
EBindFlags
Bind flags enumeration.
Definition: Flags.h:64
@ VertexBuffer
The buffer can be bound as input to the vertex shader stage as a vertex buffer.
Definition: Flags.h:68
@ IndexBuffer
The buffer can be bound as input to the vertex shader stage as an index buffer.
Definition: Flags.h:70
bool empty() const
If the buffer is empty. Note that an empty buffer may still have reserved storage.
Definition: Buffer.h:65
size_t size() const
Size of the buffer in bytes.
Definition: Buffer.h:62
void * data()
Get a pointer to the buffer data.
Definition: Buffer.h:74
Contains a stream of data used by Mesh resources.
Definition: Mesh.h:80
uint32_t offset
Byte offset from the start of the buffer.
Definition: Mesh.h:102
VertexFormatHandle format
A pointer to the format describing the contents of the byte buffer.
Definition: Mesh.h:99
uint32_t stride
Element stride.
Definition: Mesh.h:105
Cogs::Core::ResourceBufferHandle buffer
Data buffer.
Definition: Mesh.h:96
@ StreamsChanged
One or more of the data streams in the mesh changed.
Definition: Mesh.h:59
@ IndexesChanged
The index data of the mesh changed.
Definition: Mesh.h:61
VertexFormatHandle vertexFormats[maxStreams]
static constexpr size_t maxStreams
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
bool isIndexed() const
If the mesh uses indexed geometry.
Definition: Mesh.h:953
constexpr bool isMeshFlagSet(MeshFlags::EMeshFlags flag) const
Check if the given mesh flag(s) is set.
Definition: Mesh.h:683
bool hasStream(VertexDataType::EVertexDataType type) const
Check if the Mesh has a DataStream for the given type.
Definition: Mesh.h:933
void unsetMeshFlag(MeshFlags::EMeshFlags flag)
Unset the given mesh flag.
Definition: Mesh.h:671
DataStream & getStream(const VertexDataType::EVertexDataType dataType)
Get the stream corresponding to the given dataType.
Definition: Mesh.cpp:85
uint32_t getCount() const
Get the vertex count of the mesh.
Definition: Mesh.h:1012
StringView getName() const
Get the name of the resource.
Definition: ResourceBase.h:307
void unsetFlag(ResourceFlags flag)
Unset the given flag.
Definition: ResourceBase.h:236
void attachResource(RenderResource *attachment)
Attach the given GPU resource to the resource.
Definition: ResourceBase.h:261
RenderResource * getAttachedResource() const
Get the attached resource.
Definition: ResourceBase.h:275
EVertexDataType
Contains data types.
Definition: Mesh.h:26
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
handle_type handle
Internal resource handle.
Definition: Common.h:75
Provides buffer management functionality.
Definition: IBuffers.h:13
virtual VertexArrayObjectHandle loadVertexArrayObject(const EffectHandle effectHandle, const VertexBufferHandle *vertexBufferHandles, const size_t vertexBufferCount, const VertexFormat *const *vertexFormats=nullptr, const uint32_t *vertexBufferStrides=nullptr, const uint32_t *vertexBufferOffsets=nullptr, const IndexBufferHandle indexBufferHandle=IndexBufferHandle::NoHandle, uint32_t indexBufferStride=0)=0
Create a vertex array object that encapsulates binding of a set of vertex buffers and an optional ind...
virtual void annotate(BufferHandle handle, const StringView &name)
Associate a name with an object for use in graphics debugging.
Definition: IBuffers.h:17
virtual BufferHandle loadBuffer(const void *data, const size_t size, Usage::EUsage usage, uint32_t accessMode, uint32_t bindFlags, uint32_t stride=0)=0
Loads a new buffer using the given data to populate the buffer.
virtual void releaseBuffer(BufferHandle bufferHandle)=0
Releases the buffer with the given bufferHandle.
virtual void releaseVertexArrayObject(VertexArrayObjectHandle vertexArrayObjectHandle)=0
Releases the vertex array object with the given handle.
virtual const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.
@ Static
Buffer will be loaded once and used to render many subsequent frames without any updates.
Definition: Flags.h:28