From 75c99fe416e816f5155bfee9f30605df68fb0d58 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 15 Apr 2016 00:45:51 -0700 Subject: [PATCH] Working on GPU library test code --- tests/gpu-test/src/main.cpp | 474 +++++++++++++++++++++++------------- 1 file changed, 307 insertions(+), 167 deletions(-) diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index d1cd4389a7..1bb02b8101 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -38,9 +38,11 @@ #include #include +#include + #include #include -#include +#include #include "unlit_frag.h" #include "unlit_vert.h" @@ -83,6 +85,93 @@ public: uint32_t toCompactColor(const glm::vec4& color); + +const char* VERTEX_SHADER = R"SHADER( +#version 450 core + +layout(location = 0) in vec4 inPosition; +layout(location = 3) in vec2 inTexCoord0; + +struct TransformObject { + mat4 _model; + mat4 _modelInverse; +}; + +layout(location=15) in ivec2 _drawCallInfo; + +uniform samplerBuffer transformObjectBuffer; + +TransformObject getTransformObject() { + int offset = 8 * _drawCallInfo.x; + TransformObject object; + object._model[0] = texelFetch(transformObjectBuffer, offset); + object._model[1] = texelFetch(transformObjectBuffer, offset + 1); + object._model[2] = texelFetch(transformObjectBuffer, offset + 2); + object._model[3] = texelFetch(transformObjectBuffer, offset + 3); + + object._modelInverse[0] = texelFetch(transformObjectBuffer, offset + 4); + object._modelInverse[1] = texelFetch(transformObjectBuffer, offset + 5); + object._modelInverse[2] = texelFetch(transformObjectBuffer, offset + 6); + object._modelInverse[3] = texelFetch(transformObjectBuffer, offset + 7); + + return object; +} + +struct TransformCamera { + mat4 _view; + mat4 _viewInverse; + mat4 _projectionViewUntranslated; + mat4 _projection; + mat4 _projectionInverse; + vec4 _viewport; +}; + +layout(std140) uniform transformCameraBuffer { + TransformCamera _camera; +}; + +TransformCamera getTransformCamera() { + return _camera; +} + +// the interpolated normal +out vec2 _texCoord0; + +void main(void) { + _texCoord0 = inTexCoord0.st; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + { // transformModelToClipPos + vec4 eyeWAPos; + { // _transformModelToEyeWorldAlignedPos + highp mat4 _mv = obj._model; + _mv[3].xyz -= cam._viewInverse[3].xyz; + highp vec4 _eyeWApos = (_mv * inPosition); + eyeWAPos = _eyeWApos; + } + gl_Position = cam._projectionViewUntranslated * eyeWAPos; + } + +})SHADER"; + +const char* FRAGMENT_SHADER = R"SHADER( +#version 450 core + +uniform sampler2D originalTexture; + +in vec2 _texCoord0; + +layout(location = 0) out vec4 _fragColor0; + +void main(void) { + //_fragColor0 = vec4(_texCoord0, 0.0, 1.0); + _fragColor0 = texture(originalTexture, _texCoord0); +} +)SHADER"; + + gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings) { auto vs = gpu::Shader::createVertex(vertexShaderSrc); auto fs = gpu::Shader::createPixel(fragmentShaderSrc); @@ -125,6 +214,7 @@ class QTestWindow : public QWindow { glm::mat4 _projectionMatrix; RateCounter fps; QTime _time; + glm::mat4 _camera; protected: void renderText(); @@ -145,7 +235,7 @@ public: setGLFormatVersion(format); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); format.setOption(QSurfaceFormat::DebugContext); - format.setSwapInterval(0); + //format.setSwapInterval(0); setFormat(format); @@ -158,19 +248,22 @@ public: gpu::Context::init(); _context = std::make_shared(); - + makeCurrent(); auto shader = makeShader(unlit_vert, unlit_frag, gpu::Shader::BindingSet{}); auto state = std::make_shared(); state->setMultisampleEnable(true); state->setDepthTest(gpu::State::DepthTest { true }); _pipeline = gpu::Pipeline::create(shader, state); + + // Clear screen gpu::Batch batch; batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 1.0, 0.0, 0.5, 1.0 }); _context->render(batch); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); resize(QSize(800, 600)); @@ -181,182 +274,229 @@ public: virtual ~QTestWindow() { } + void updateCamera() { + float t = _time.elapsed() * 1e-4f; + glm::vec3 unitscale { 1.0f }; + glm::vec3 up { 0.0f, 1.0f, 0.0f }; + + float distance = 3.0f; + glm::vec3 camera_position { distance * sinf(t), 0.5f, distance * cosf(t) }; + + static const vec3 camera_focus(0); + static const vec3 camera_up(0, 1, 0); + _camera = glm::inverse(glm::lookAt(camera_position, camera_focus, up)); + } + + + void drawFloorGrid(gpu::Batch& batch) { + auto geometryCache = DependencyManager::get(); + // Render grid on xz plane (not the optimal way to do things, but w/e) + // Note: GeometryCache::renderGrid will *not* work, as it is apparenly unaffected by batch rotations and renders xy only + static const std::string GRID_INSTANCE = "Grid"; + static auto compactColor1 = toCompactColor(vec4 { 0.35f, 0.25f, 0.15f, 1.0f }); + static auto compactColor2 = toCompactColor(vec4 { 0.15f, 0.25f, 0.35f, 1.0f }); + static std::vector transforms; + static gpu::BufferPointer colorBuffer; + if (!transforms.empty()) { + transforms.reserve(200); + colorBuffer = std::make_shared(); + for (int i = 0; i < 100; ++i) { + { + glm::mat4 transform = glm::translate(mat4(), vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transforms.push_back(transform); + colorBuffer->append(compactColor1); + } + + { + glm::mat4 transform = glm::mat4_cast(quat(vec3(0, PI / 2.0f, 0))); + transform = glm::translate(transform, vec3(0, -1, -50 + i)); + transform = glm::scale(transform, vec3(100, 1, 1)); + transforms.push_back(transform); + colorBuffer->append(compactColor2); + } + } + } + auto pipeline = geometryCache->getSimplePipeline(); + for (auto& transform : transforms) { + batch.setModelTransform(transform); + batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + batch.setViewTransform(_camera); + batch.setPipeline(_pipeline); + geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count(), colorBuffer); + }); + } + } + + void drawSimpleShapes(gpu::Batch& batch) { + auto geometryCache = DependencyManager::get(); + static const size_t ITEM_COUNT = 1000; + static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT; + static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT; + + static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA }; + + static std::vector transforms; + static std::vector colors; + static gpu::BufferPointer colorBuffer; + static gpu::BufferView colorView; + static gpu::BufferView instanceXfmView; + if (!colorBuffer) { + colorBuffer = std::make_shared(); + + static const float ITEM_RADIUS = 20; + static const vec3 ITEM_TRANSLATION { 0, 0, -ITEM_RADIUS }; + for (size_t i = 0; i < TYPE_COUNT; ++i) { + GeometryCache::Shape shape = SHAPE[i]; + GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape]; + //indirectCommand._count + float startingInterval = ITEM_INTERVAL * i; + for (size_t j = 0; j < ITEM_COUNT; ++j) { + float theta = j * SHAPE_INTERVAL + startingInterval; + auto transform = glm::rotate(mat4(), theta, Vectors::UP); + transform = glm::rotate(transform, (randFloat() - 0.5f) * PI / 4.0f, Vectors::UNIT_X); + transform = glm::translate(transform, ITEM_TRANSLATION); + transform = glm::scale(transform, vec3(randFloat() / 2.0f + 0.5f)); + transforms.push_back(transform); + auto color = vec4 { randomColorValue(64), randomColorValue(64), randomColorValue(64), 255 }; + color /= 255.0f; + colors.push_back(color); + colorBuffer->append(toCompactColor(color)); + } + } + colorView = gpu::BufferView(colorBuffer, COLOR_ELEMENT); + } + + batch.setViewTransform(_camera); + batch.setPipeline(_pipeline); + batch.setInputFormat(getInstancedSolidStreamFormat()); + for (size_t i = 0; i < TYPE_COUNT; ++i) { + GeometryCache::Shape shape = SHAPE[i]; + GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape]; + batch.setInputBuffer(gpu::Stream::COLOR, colorView); + for (size_t j = 0; j < ITEM_COUNT; ++j) { + batch.setModelTransform(transforms[j]); + shapeData.draw(batch); + } + } + } + + void drawCenterShape(gpu::Batch& batch) { + // Render unlit cube + sphere + static auto startUsecs = usecTimestampNow(); + float seconds = getSeconds(startUsecs); + seconds /= 4.0f; + batch.setModelTransform(Transform()); + batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); + + bool wire = (seconds - floorf(seconds) > 0.5f); + auto geometryCache = DependencyManager::get(); + int shapeIndex = ((int)seconds) % TYPE_COUNT; + if (wire) { + geometryCache->renderWireShape(batch, SHAPE[shapeIndex]); + } else { + geometryCache->renderShape(batch, SHAPE[shapeIndex]); + } + + batch.setModelTransform(Transform().setScale(2.05f)); + batch._glColor4f(1, 1, 1, 1); + geometryCache->renderWireCube(batch); + } + + void drawTerrain(gpu::Batch& batch) { + auto geometryCache = DependencyManager::get(); + static std::once_flag once; + static gpu::BufferPointer vertexBuffer { std::make_shared() }; + static gpu::BufferPointer indexBuffer { std::make_shared() }; + + static gpu::BufferView positionView; + static gpu::BufferView textureView; + static gpu::Stream::FormatPointer vertexFormat { std::make_shared() }; + + static gpu::TexturePointer texture; + static gpu::PipelinePointer pipeline; + std::call_once(once, [&] { + static const uint SHAPE_VERTEX_STRIDE = sizeof(glm::vec4) * 2; // position, normals, textures + static const uint SHAPE_TEXTURES_OFFSET = sizeof(glm::vec4); + static const gpu::Element POSITION_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element TEXTURE_ELEMENT { gpu::VEC2, gpu::FLOAT, gpu::UV }; + static const gpu::Type SHAPE_INDEX_TYPE = gpu::UINT16; + static const uint SHAPE_INDEX_SIZE = sizeof(gpu::uint16); + std::vector vertices; + const int MINX = -1000; + const int MAXX = 1000; + // top + vertices.push_back(vec4(MAXX, 0, MAXX, 1)); + vertices.push_back(vec4(MAXX, MAXX, 0, 0)); + + vertices.push_back(vec4(MAXX, 0, MINX, 1)); + vertices.push_back(vec4(MAXX, 0, 0, 0)); + + vertices.push_back(vec4(MINX, 0, MINX, 1)); + vertices.push_back(vec4(0, 0, 0, 0)); + + vertices.push_back(vec4(MINX, 0, MAXX, 1)); + vertices.push_back(vec4(0, MAXX, 0, 0)); + + vertexBuffer->append(vertices); + indexBuffer->append(std::vector({ 0, 1, 2, 2, 3, 0 })); + + positionView = gpu::BufferView(vertexBuffer, 0, vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, POSITION_ELEMENT); + textureView = gpu::BufferView(vertexBuffer, SHAPE_TEXTURES_OFFSET, vertexBuffer->getSize(), SHAPE_VERTEX_STRIDE, TEXTURE_ELEMENT); + texture = DependencyManager::get()->getImageTexture("C:/Users/bdavis/Git/openvr/samples/bin/cube_texture.png"); + //texture = DependencyManager::get()->getImageTexture("H:/test.png"); + //texture = DependencyManager::get()->getImageTexture("H:/crate_blue.fbm/lambert8SG_Normal_OpenGL.png"); + + auto shader = makeShader(VERTEX_SHADER, FRAGMENT_SHADER, gpu::Shader::BindingSet {}); + auto state = std::make_shared(); + state->setMultisampleEnable(false); + state->setDepthTest(gpu::State::DepthTest { true }); + pipeline = gpu::Pipeline::create(shader, state); + vertexFormat->setAttribute(gpu::Stream::POSITION); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD); + + }); + batch.setPipeline(pipeline); + batch.setInputBuffer(gpu::Stream::POSITION, positionView); + batch.setInputBuffer(gpu::Stream::TEXCOORD, textureView); + batch.setIndexBuffer(gpu::UINT16, indexBuffer, 0); + batch.setInputFormat(vertexFormat); + + batch.setResourceTexture(0, texture); + batch.setModelTransform(glm::translate(glm::mat4(), vec3(0, -0.1, 0))); + batch.drawIndexed(gpu::TRIANGLES, 6, 0); + + batch.setResourceTexture(0, DependencyManager::get()->getBlueTexture()); + batch.setModelTransform(glm::translate(glm::mat4(), vec3(0, -0.2, 0))); + batch.drawIndexed(gpu::TRIANGLES, 6, 0); + } + void draw() { // Attempting to draw before we're visible and have a valid size will // produce GL errors. if (!isVisible() || _size.width() <= 0 || _size.height() <= 0) { return; } + updateCamera(); makeCurrent(); gpu::Batch batch; - batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.0f, 0.0f, 0.0f, 1.0f }); + batch.resetStages(); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLORS, { 0.0f, 0.1f, 0.2f, 1.0f }); batch.clearDepthFramebuffer(1e4); batch.setViewportTransform({ 0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio() }); batch.setProjectionTransform(_projectionMatrix); - float t = _time.elapsed() * 1e-3f; - glm::vec3 unitscale { 1.0f }; - glm::vec3 up { 0.0f, 1.0f, 0.0f }; - - float distance = 3.0f; - glm::vec3 camera_position{ distance * sinf(t), 0.0f, distance * cosf(t) }; - - static const vec3 camera_focus(0); - static const vec3 camera_up(0, 1, 0); - glm::mat4 camera = glm::inverse(glm::lookAt(camera_position, camera_focus, up)); - batch.setViewTransform(camera); + batch.setViewTransform(_camera); batch.setPipeline(_pipeline); batch.setModelTransform(Transform()); - auto geometryCache = DependencyManager::get(); - - // Render grid on xz plane (not the optimal way to do things, but w/e) - // Note: GeometryCache::renderGrid will *not* work, as it is apparenly unaffected by batch rotations and renders xy only - { - static const std::string GRID_INSTANCE = "Grid"; - static auto compactColor1 = toCompactColor(vec4{ 0.35f, 0.25f, 0.15f, 1.0f }); - static auto compactColor2 = toCompactColor(vec4{ 0.15f, 0.25f, 0.35f, 1.0f }); - static std::vector transforms; - static gpu::BufferPointer colorBuffer; - if (!transforms.empty()) { - transforms.reserve(200); - colorBuffer = std::make_shared(); - for (int i = 0; i < 100; ++i) { - { - glm::mat4 transform = glm::translate(mat4(), vec3(0, -1, -50 + i)); - transform = glm::scale(transform, vec3(100, 1, 1)); - transforms.push_back(transform); - colorBuffer->append(compactColor1); - } - - { - glm::mat4 transform = glm::mat4_cast(quat(vec3(0, PI / 2.0f, 0))); - transform = glm::translate(transform, vec3(0, -1, -50 + i)); - transform = glm::scale(transform, vec3(100, 1, 1)); - transforms.push_back(transform); - colorBuffer->append(compactColor2); - } - } - } - - auto pipeline = geometryCache->getSimplePipeline(); - for (auto& transform : transforms) { - batch.setModelTransform(transform); - batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - batch.setViewTransform(camera); - batch.setPipeline(_pipeline); - geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count(), colorBuffer); - }); - } - } - - { - static const size_t ITEM_COUNT = 1000; - static const float SHAPE_INTERVAL = (PI * 2.0f) / ITEM_COUNT; - static const float ITEM_INTERVAL = SHAPE_INTERVAL / TYPE_COUNT; - - static const gpu::Element POSITION_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; - static const gpu::Element NORMAL_ELEMENT{ gpu::VEC3, gpu::FLOAT, gpu::XYZ }; - static const gpu::Element COLOR_ELEMENT{ gpu::VEC4, gpu::NUINT8, gpu::RGBA }; - static const gpu::Element TRANSFORM_ELEMENT{ gpu::MAT4, gpu::FLOAT, gpu::XYZW }; - - - static std::vector transforms; - static std::vector colors; - static gpu::BufferPointer indirectBuffer; - static gpu::BufferPointer transformBuffer; - static gpu::BufferPointer colorBuffer; - static gpu::BufferView colorView; - static gpu::BufferView instanceXfmView; - - if (!transformBuffer) { - transformBuffer = std::make_shared(); - colorBuffer = std::make_shared(); - indirectBuffer = std::make_shared(); - - static const float ITEM_RADIUS = 20; - static const vec3 ITEM_TRANSLATION{ 0, 0, -ITEM_RADIUS }; - for (size_t i = 0; i < TYPE_COUNT; ++i) { - GeometryCache::Shape shape = SHAPE[i]; - GeometryCache::ShapeData shapeData = geometryCache->_shapes[shape]; - { - gpu::Batch::DrawIndexedIndirectCommand indirectCommand; - indirectCommand._count = (uint)shapeData._indexCount; - indirectCommand._instanceCount = ITEM_COUNT; - indirectCommand._baseInstance = (uint)(i * ITEM_COUNT); - indirectCommand._firstIndex = (uint)shapeData._indexOffset / 2; - indirectCommand._baseVertex = 0; - indirectBuffer->append(indirectCommand); - } - - //indirectCommand._count - float startingInterval = ITEM_INTERVAL * i; - for (size_t j = 0; j < ITEM_COUNT; ++j) { - float theta = j * SHAPE_INTERVAL + startingInterval; - auto transform = glm::rotate(mat4(), theta, Vectors::UP); - transform = glm::rotate(transform, (randFloat() - 0.5f) * PI / 4.0f, Vectors::UNIT_X); - transform = glm::translate(transform, ITEM_TRANSLATION); - transform = glm::scale(transform, vec3(randFloat() / 2.0f + 0.5f)); - transformBuffer->append(transform); - transforms.push_back(transform); - auto color = vec4{ randomColorValue(64), randomColorValue(64), randomColorValue(64), 255 }; - color /= 255.0f; - colors.push_back(color); - colorBuffer->append(toCompactColor(color)); - } - } - colorView = gpu::BufferView(colorBuffer, COLOR_ELEMENT); - instanceXfmView = gpu::BufferView(transformBuffer, TRANSFORM_ELEMENT); - } - -#if 1 - GeometryCache::ShapeData shapeData = geometryCache->_shapes[GeometryCache::Icosahedron]; - { - batch.setViewTransform(camera); - batch.setModelTransform(Transform()); - batch.setPipeline(_pipeline); - batch.setInputFormat(getInstancedSolidStreamFormat()); - batch.setInputBuffer(gpu::Stream::COLOR, colorView); - batch.setIndirectBuffer(indirectBuffer); - shapeData.setupBatch(batch); - batch.multiDrawIndexedIndirect(TYPE_COUNT, gpu::TRIANGLES); - } -#else - batch.setViewTransform(camera); - batch.setPipeline(_pipeline); - for (size_t i = 0; i < TYPE_COUNT; ++i) { - GeometryCache::Shape shape = SHAPE[i]; - for (size_t j = 0; j < ITEM_COUNT; ++j) { - int index = i * ITEM_COUNT + j; - batch.setModelTransform(transforms[index]); - const vec4& color = colors[index]; - batch._glColor4f(color.r, color.g, color.b, 1.0); - geometryCache->renderShape(batch, shape); - } - } -#endif - } - - // Render unlit cube + sphere - static auto startUsecs = usecTimestampNow(); - float seconds = getSeconds(startUsecs); - - seconds /= 4.0f; - int shapeIndex = ((int)seconds) % TYPE_COUNT; - bool wire = (seconds - floorf(seconds) > 0.5f); - batch.setModelTransform(Transform()); - batch._glColor4f(0.8f, 0.25f, 0.25f, 1.0f); - - if (wire) { - geometryCache->renderWireShape(batch, SHAPE[shapeIndex]); - } else { - geometryCache->renderShape(batch, SHAPE[shapeIndex]); - } - - batch.setModelTransform(Transform().setScale(2.05f)); - batch._glColor4f(1, 1, 1, 1); - geometryCache->renderWireCube(batch); + //drawFloorGrid(batch); + //drawSimpleShapes(batch); + drawCenterShape(batch); + drawTerrain(batch); _context->render(batch); _qGlContext.swapBuffers(this); @@ -387,12 +527,12 @@ protected: int main(int argc, char** argv) { QGuiApplication app(argc, argv); QTestWindow window; - QTimer timer; - timer.setInterval(0); - app.connect(&timer, &QTimer::timeout, &app, [&] { + auto timer = new QTimer(&app); + timer->setInterval(0); + app.connect(timer, &QTimer::timeout, &app, [&] { window.draw(); }); - timer.start(); + timer->start(); app.exec(); return 0; }