From ffe9dac56488ebfc9f5c37c4e400f4f5469a8a46 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 26 Dec 2017 17:29:28 +0100 Subject: Add device memory, device frame. Rendering works --- include/RenderBackend/OpenGL/CompiledShader.hpp | 9 ++++- include/RenderBackend/OpenGL/DeviceFrame.hpp | 24 ++++++++++++ include/RenderBackend/OpenGL/DeviceMemory.hpp | 42 +++++++++++++++----- include/RenderBackend/OpenGL/ShaderProgram.hpp | 4 +- include/RenderBackend/OpenGL/ShaderVec.hpp | 10 +++++ include/RenderBackend/OpenGL/VertexShader.hpp | 6 ++- src/RenderBackend/OpenGL/CompiledShader.cpp | 7 +++- src/RenderBackend/OpenGL/DeviceFrame.cpp | 36 +++++++++++++++++ src/RenderBackend/OpenGL/DeviceMemory.cpp | 51 ++++++++++++++++++++----- src/RenderBackend/OpenGL/PixelShader.cpp | 2 +- src/RenderBackend/OpenGL/ShaderProgram.cpp | 17 ++++++++- src/RenderBackend/OpenGL/ShaderVec.cpp | 31 +++++++++++++++ src/RenderBackend/OpenGL/VertexShader.cpp | 16 ++++++-- src/main.cpp | 29 +++++++++----- 14 files changed, 240 insertions(+), 44 deletions(-) create mode 100644 include/RenderBackend/OpenGL/DeviceFrame.hpp create mode 100644 src/RenderBackend/OpenGL/DeviceFrame.cpp diff --git a/include/RenderBackend/OpenGL/CompiledShader.hpp b/include/RenderBackend/OpenGL/CompiledShader.hpp index 67e6418..8d2ee84 100644 --- a/include/RenderBackend/OpenGL/CompiledShader.hpp +++ b/include/RenderBackend/OpenGL/CompiledShader.hpp @@ -1,6 +1,8 @@ #pragma once #include "../../types.hpp" +#include +#include namespace amalgine { @@ -22,9 +24,14 @@ namespace amalgine public: ~CompiledPixelShader(); u32 getShaderId() const; + const auto& getPixelAttributes() const + { + return pixelAttributes; + } private: - CompiledPixelShader(u32 _shaderId); + CompiledPixelShader(u32 _shaderId, std::unordered_map &&_pixelAttributes); private: u32 shaderId; + std::unordered_map pixelAttributes; }; } diff --git a/include/RenderBackend/OpenGL/DeviceFrame.hpp b/include/RenderBackend/OpenGL/DeviceFrame.hpp new file mode 100644 index 0000000..12e578a --- /dev/null +++ b/include/RenderBackend/OpenGL/DeviceFrame.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "../../types.hpp" +#include "../../utils.hpp" +#include + +namespace amalgine +{ + class DeviceMemory; + + class DeviceFrame + { + DISABLE_COPY(DeviceFrame) + public: + DeviceFrame(); + ~DeviceFrame(); + + DeviceMemory* alloc(); + void draw(); + private: + u32 vertexArrayObjectId; + std::vector buffers; + }; +} diff --git a/include/RenderBackend/OpenGL/DeviceMemory.hpp b/include/RenderBackend/OpenGL/DeviceMemory.hpp index 974c7cf..163b0ad 100644 --- a/include/RenderBackend/OpenGL/DeviceMemory.hpp +++ b/include/RenderBackend/OpenGL/DeviceMemory.hpp @@ -2,27 +2,49 @@ #include "../../DataView.hpp" #include "../../utils.hpp" +#include namespace amalgine { + class DeviceMemoryEmpty : public std::runtime_error + { + public: + DeviceMemoryEmpty(const std::string &errMsg) : std::runtime_error(errMsg) {} + }; + class DeviceMemory { DISABLE_COPY(DeviceMemory) + friend class DeviceFrame; + friend class ShaderInputVec4; public: - DeviceMemory(); - ~DeviceMemory(); - - // Uploaded once, drawn many times - void copyAsStatic(const DataView &data); + enum class StorageType + { + // Uploaded once, drawn many times + STATIC, + + // Created once, changed from time to time but drawn many times more than that + DYNAMIC, + + // Uploaded once, drawn once (for example data that is changed every frame) + STREAM + }; - // Created once, changed from time to time but drawn many times more than that - void copyAsDynamic(const DataView &data); + enum class PrimitiveType + { + TRIANGLE + }; - // Uploaded once, drawn once (for example data that is changed every frame) - void copyAsStream(const DataView &data); + ~DeviceMemory(); + void copy(const DataView &data, StorageType storageType, PrimitiveType primitiveType = PrimitiveType::TRIANGLE); + void draw(); private: - void copy(const DataView &data, i32 storageType); + DeviceMemory(); + void operator delete(void *data); + void use() const; private: u32 vertexBufferObjectId; + u32 primitiveType; + u32 numVertices; }; } diff --git a/include/RenderBackend/OpenGL/ShaderProgram.hpp b/include/RenderBackend/OpenGL/ShaderProgram.hpp index a3e8a0f..2b1c5b4 100644 --- a/include/RenderBackend/OpenGL/ShaderProgram.hpp +++ b/include/RenderBackend/OpenGL/ShaderProgram.hpp @@ -26,8 +26,8 @@ namespace amalgine ShaderProgram(); ~ShaderProgram(); - bool addVertexShader(CompiledVertexShader *vertexShader); - bool addPixelShader(CompiledPixelShader *pixelShader); + bool setVertexShader(CompiledVertexShader *vertexShader); + bool setPixelShader(CompiledPixelShader *pixelShader); Result build(); void use(); diff --git a/include/RenderBackend/OpenGL/ShaderVec.hpp b/include/RenderBackend/OpenGL/ShaderVec.hpp index 10e628c..a5163ba 100644 --- a/include/RenderBackend/OpenGL/ShaderVec.hpp +++ b/include/RenderBackend/OpenGL/ShaderVec.hpp @@ -1,6 +1,7 @@ #pragma once #include "../../types.hpp" +#include "../../RenderBackend/OpenGL/DeviceMemory.hpp" #include namespace amalgine @@ -8,11 +9,20 @@ namespace amalgine class VertexShader; class PixelShader; + enum class AttributeType + { + NONE, + VEC2 + }; + + AttributeType getAttributeTypeByName(const char *attributeName); + class ShaderInputVec2 { friend class VertexShader; public: const std::string& getName() const; + void setData(const DeviceMemory &data); private: ShaderInputVec2(VertexShader *_vertexShader, i32 _attributeIndex) : vertexShader(_vertexShader), diff --git a/include/RenderBackend/OpenGL/VertexShader.hpp b/include/RenderBackend/OpenGL/VertexShader.hpp index 43a5dd8..aaf8b24 100644 --- a/include/RenderBackend/OpenGL/VertexShader.hpp +++ b/include/RenderBackend/OpenGL/VertexShader.hpp @@ -3,6 +3,7 @@ #include "../../DataView.hpp" #include "../../utils.hpp" #include "../../Result.hpp" +#include "CommonShader.hpp" #include "ShaderVec.hpp" #include #include @@ -51,7 +52,8 @@ namespace amalgine public: VertexShader(); - const std::string& getInputAttributeName(i32 attributeIndex); + const std::string& getInputAttributeName(i32 attributeIndex) const; + AttributeType getInputAttributeType(i32 attributeIndex) const; ShaderInputVec2 defineInputVec2(const std::string &name); void defineMain(VertexShaderMainFunc mainFunc); Result compile(); @@ -71,7 +73,7 @@ namespace amalgine int locationCounter; i32 maxVertexAttribs; // Could make this static std::unordered_map vertexAttributes; - std::vector vertexAttributeNames; + std::vector vertexAttributeNames; bool mainFuncDefined; }; } diff --git a/src/RenderBackend/OpenGL/CompiledShader.cpp b/src/RenderBackend/OpenGL/CompiledShader.cpp index 6707b7a..f4a1fec 100644 --- a/src/RenderBackend/OpenGL/CompiledShader.cpp +++ b/src/RenderBackend/OpenGL/CompiledShader.cpp @@ -1,6 +1,8 @@ #include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" +using namespace std; + namespace amalgine { CompiledVertexShader::CompiledVertexShader(u32 _shaderId) : @@ -19,8 +21,9 @@ namespace amalgine return shaderId; } - CompiledPixelShader::CompiledPixelShader(u32 _shaderId) : - shaderId(_shaderId) + CompiledPixelShader::CompiledPixelShader(u32 _shaderId, unordered_map &&_pixelAttributes) : + shaderId(_shaderId), + pixelAttributes(_pixelAttributes) { } diff --git a/src/RenderBackend/OpenGL/DeviceFrame.cpp b/src/RenderBackend/OpenGL/DeviceFrame.cpp new file mode 100644 index 0000000..9d60597 --- /dev/null +++ b/src/RenderBackend/OpenGL/DeviceFrame.cpp @@ -0,0 +1,36 @@ +#include "../../../include/RenderBackend/OpenGL/DeviceFrame.hpp" +#include "../../../include/RenderBackend/OpenGL/DeviceMemory.hpp" +#include "../../../include/RenderBackend/OpenGL/opengl.hpp" + +namespace amalgine +{ + DeviceFrame::DeviceFrame() + { + glGenVertexArrays(1, &vertexArrayObjectId); + } + + DeviceFrame::~DeviceFrame() + { + for(DeviceMemory *deviceMemory : buffers) + { + delete deviceMemory; + } + glDeleteVertexArrays(1, &vertexArrayObjectId); + } + + DeviceMemory* DeviceFrame::alloc() + { + glBindVertexArray(vertexArrayObjectId); + DeviceMemory *deviceMemory = new DeviceMemory(); + buffers.push_back(deviceMemory); + return deviceMemory; + } + + void DeviceFrame::draw() + { + for(DeviceMemory *deviceMemory : buffers) + { + deviceMemory->draw(); + } + } +} diff --git a/src/RenderBackend/OpenGL/DeviceMemory.cpp b/src/RenderBackend/OpenGL/DeviceMemory.cpp index 9e33ac9..faf2943 100644 --- a/src/RenderBackend/OpenGL/DeviceMemory.cpp +++ b/src/RenderBackend/OpenGL/DeviceMemory.cpp @@ -3,7 +3,33 @@ namespace amalgine { - DeviceMemory::DeviceMemory() + u32 getOpenglStorageType(DeviceMemory::StorageType storageType) + { + switch(storageType) + { + case DeviceMemory::StorageType::STATIC: return GL_STATIC_DRAW; + case DeviceMemory::StorageType::DYNAMIC: return GL_DYNAMIC_DRAW; + case DeviceMemory::StorageType::STREAM: return GL_STREAM_DRAW; + } + } + + u32 getOpenglPrimitiveType(DeviceMemory::PrimitiveType primitiveType) + { + switch(primitiveType) + { + case DeviceMemory::PrimitiveType::TRIANGLE: return GL_TRIANGLES; + } + } + + u32 getPrimitiveTypePointsPerVertices(DeviceMemory::PrimitiveType primitiveType) + { + switch(primitiveType) + { + case DeviceMemory::PrimitiveType::TRIANGLE: return 3; + } + } + + DeviceMemory::DeviceMemory() : primitiveType(0), numVertices(0) { glGenBuffers(1, &vertexBufferObjectId); } @@ -13,24 +39,29 @@ namespace amalgine glDeleteBuffers(1, &vertexBufferObjectId); } - void DeviceMemory::copyAsStatic(const DataView &data) + void DeviceMemory::operator delete(void *data) { - copy(data, GL_STATIC_DRAW); + free(data); } - void DeviceMemory::copyAsDynamic(const DataView &data) + void DeviceMemory::use() const { - copy(data, GL_DYNAMIC_DRAW); + // TODO: Bind vao here? + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); } - void DeviceMemory::copyAsStream(const DataView &data) + void DeviceMemory::copy(const DataView &data, StorageType storageType, PrimitiveType primitiveType) { - copy(data, GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); + glBufferData(GL_ARRAY_BUFFER, data.getByteSize(), data.data, getOpenglStorageType(storageType)); + this->primitiveType = getOpenglPrimitiveType(primitiveType); + numVertices = getPrimitiveTypePointsPerVertices(primitiveType); } - void DeviceMemory::copy(const DataView &data, i32 storageType) + void DeviceMemory::draw() { - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectId); - glBufferData(GL_ARRAY_BUFFER, data.getByteSize(), data.data, storageType); + if(primitiveType == 0) + throw DeviceMemoryEmpty("Unable to draw buffer as no data has been copied to device memory"); + glDrawArrays(primitiveType, 0, 3); } } diff --git a/src/RenderBackend/OpenGL/PixelShader.cpp b/src/RenderBackend/OpenGL/PixelShader.cpp index 2af68e5..8aa4d9a 100644 --- a/src/RenderBackend/OpenGL/PixelShader.cpp +++ b/src/RenderBackend/OpenGL/PixelShader.cpp @@ -131,7 +131,7 @@ namespace amalgine { if(!compileLog.empty()) printf("Pixel shader compile log:\n%s", compileLog.c_str()); - return Result::Ok(new CompiledPixelShader(fragmentShaderId)); + return Result::Ok(new CompiledPixelShader(fragmentShaderId, move(pixelAttributes))); } else return Result::Err(compileLog); diff --git a/src/RenderBackend/OpenGL/ShaderProgram.cpp b/src/RenderBackend/OpenGL/ShaderProgram.cpp index f76903e..40f5b6c 100644 --- a/src/RenderBackend/OpenGL/ShaderProgram.cpp +++ b/src/RenderBackend/OpenGL/ShaderProgram.cpp @@ -36,17 +36,30 @@ namespace amalgine // TODO: Before adding shader to program, check if it has already been added - bool ShaderProgram::addVertexShader(CompiledVertexShader *vertexShader) + bool ShaderProgram::setVertexShader(CompiledVertexShader *vertexShader) { + if(!vertexShader) return false; + // TODO: Do not allow adding shader if the program has already been built glAttachShader(shaderProgramId, vertexShader->getShaderId()); return true; } - bool ShaderProgram::addPixelShader(CompiledPixelShader *pixelShader) + bool ShaderProgram::setPixelShader(CompiledPixelShader *pixelShader) { + if(!pixelShader) return false; + // TODO: Do not allow adding shader if the program has already been built glAttachShader(shaderProgramId, pixelShader->getShaderId()); + + const auto &pixelAttributes = pixelShader->getPixelAttributes(); + for(const auto &pixelAttribute : pixelAttributes) + { + const string &attributeName = pixelAttribute.first; + i32 attributeLocation = pixelAttribute.second; + glBindFragDataLocation(shaderProgramId, attributeLocation, attributeName.c_str()); + } + return true; } diff --git a/src/RenderBackend/OpenGL/ShaderVec.cpp b/src/RenderBackend/OpenGL/ShaderVec.cpp index 6411650..3bbe0be 100644 --- a/src/RenderBackend/OpenGL/ShaderVec.cpp +++ b/src/RenderBackend/OpenGL/ShaderVec.cpp @@ -2,16 +2,47 @@ #include "../../../include/RenderBackend/OpenGL/VertexShader.hpp" #include "../../../include/RenderBackend/OpenGL/PixelShader.hpp" #include "../../../include/RenderBackend/OpenGL/ShaderProgram.hpp" +#include "../../../include/RenderBackend/OpenGL/opengl.hpp" +#include +#include using namespace std; namespace amalgine { + AttributeType getAttributeTypeByName(const char *attributeName) + { + if(strncmp(attributeName, "vec2", 4) == 0) + { + return AttributeType::VEC2; + } + + return AttributeType::NONE; + } + const string& ShaderInputVec2::getName() const { return vertexShader->getInputAttributeName(attributeIndex); } + void ShaderInputVec2::setData(const DeviceMemory &data) + { + data.use(); + AttributeType attributeType = vertexShader->getInputAttributeType(attributeIndex); + switch(attributeType) + { + case AttributeType::VEC2: + { + glVertexAttribPointer(attributeIndex, 2, GL_FLOAT, GL_FALSE, 0, 0); + break; + } + default: + assert(false); + break; + } + glEnableVertexAttribArray(attributeIndex); + } + const string& ShaderOutputVec4::getName() const { return pixelShader->getOutputAttributeName(attributeIndex); diff --git a/src/RenderBackend/OpenGL/VertexShader.cpp b/src/RenderBackend/OpenGL/VertexShader.cpp index 1505ff4..ac9a159 100644 --- a/src/RenderBackend/OpenGL/VertexShader.cpp +++ b/src/RenderBackend/OpenGL/VertexShader.cpp @@ -1,5 +1,4 @@ #include "../../../include/RenderBackend/OpenGL/VertexShader.hpp" -#include "../../../include/RenderBackend/OpenGL/CommonShader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" #include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" @@ -37,10 +36,16 @@ namespace amalgine writeHeader("#version 330 core\n\n"); } - const string& VertexShader::getInputAttributeName(i32 attributeIndex) + const string& VertexShader::getInputAttributeName(i32 attributeIndex) const { assert(attributeIndex < vertexAttributeNames.size()); - return vertexAttributeNames[attributeIndex]; + return vertexAttributeNames[attributeIndex].name; + } + + AttributeType VertexShader::getInputAttributeType(i32 attributeIndex) const + { + assert(attributeIndex < vertexAttributeNames.size()); + return getAttributeTypeByName(vertexAttributeNames[attributeIndex].typeName); } ShaderInputVec2 VertexShader::defineInputVec2(const std::string &name) @@ -75,7 +80,10 @@ namespace amalgine i32 attributeIndex = locationCounter; vertexAttributes[variableName] = locationCounter; - vertexAttributeNames.push_back(variableName); + ShaderAttribute shaderAttribute; + shaderAttribute.name = variableName; + shaderAttribute.typeName = typeName; + vertexAttributeNames.push_back(shaderAttribute); writeHeader("layout(location = "); writeHeader(to_string(locationCounter)); diff --git a/src/main.cpp b/src/main.cpp index b1a0d62..0e72df0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,16 @@ #include -#include -#include -#include +#include "../include/RenderBackend/OpenGL/opengl.hpp" #include "../include/RenderBackend/OpenGL/VertexShader.hpp" #include "../include/RenderBackend/OpenGL/PixelShader.hpp" #include "../include/RenderBackend/OpenGL/ShaderProgram.hpp" #include "../include/RenderBackend/OpenGL/DeviceMemory.hpp" +#include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" + +// TODO: Disallow shader variables that begin with "gl_" as reserved variables +// start with that. What about hlsl? + +// TODO: Creating buffers etc should be somehow created/drawn using the window object, since they are associated with the window +// opengl context using namespace amalgine; using namespace std; @@ -14,7 +19,7 @@ void initGlfw(); void initGlew(); GLFWwindow *createWindow(); -CompiledVertexShader* createVertexShader(); +CompiledVertexShader* createVertexShader(const DeviceMemory &inputData); CompiledPixelShader* createPixelShader(); int main() @@ -22,22 +27,24 @@ int main() initGlfw(); GLFWwindow *window = createWindow(); + DeviceFrame frame; + f32 verticesRaw[] = { 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f }; + DeviceMemory *triangle = frame.alloc(); DataView vertices(verticesRaw, 6); - DeviceMemory triangle; - triangle.copyAsStatic(vertices); + triangle->copy(vertices, DeviceMemory::StorageType::STATIC); - CompiledVertexShader *vertexShader = createVertexShader(); + CompiledVertexShader *vertexShader = createVertexShader(*triangle); CompiledPixelShader *pixelShader = createPixelShader(); ShaderProgram shaderProgram; - shaderProgram.addVertexShader(vertexShader); - shaderProgram.addPixelShader(pixelShader); + shaderProgram.setVertexShader(vertexShader); + shaderProgram.setPixelShader(pixelShader); Result shaderBuildResult = shaderProgram.build(); if(!shaderBuildResult) { @@ -52,6 +59,7 @@ int main() glfwSetWindowShouldClose(window, GL_TRUE); shaderProgram.use(); + frame.draw(); glfwSwapBuffers(window); } @@ -102,10 +110,11 @@ GLFWwindow* createWindow() return window; } -CompiledVertexShader* createVertexShader() +CompiledVertexShader* createVertexShader(const DeviceMemory &inputData) { VertexShader vertexShader; ShaderInputVec2 inputPosition = vertexShader.defineInputVec2("position"); + inputPosition.setData(inputData); vertexShader.defineMain([&inputPosition]() { -- cgit v1.2.3