From b16812aa4d5d4bf497a97f2b55fe435efc98a2b2 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 19 May 2016 00:37:58 -0700 Subject: [PATCH] Adding GL 4.5 backend --- libraries/gpu-gl/src/gpu/gl/GLBackend.cpp | 11 +- .../gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp | 4 +- libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp | 149 ++++++++++++++ libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 85 ++++++++ .../gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp | 48 +++++ .../gpu-gl/src/gpu/gl45/GL45BackendInput.cpp | 83 ++++++++ .../gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp | 145 ++++++++++++++ .../gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp | 38 ++++ .../src/gpu/gl45/GL45BackendTexture.cpp | 181 +++++++++++++++++ .../src/gpu/gl45/GL45BackendTransform.cpp | 71 +++++++ libraries/gpu/src/gpu/null/NullBackend.h | 54 +++++ tests/gpu-test/src/TestFbx.cpp | 187 ++++++++++++++++++ tests/gpu-test/src/TestFbx.h | 35 ++++ tests/gpu-test/src/TestFloorGrid.cpp | 54 +++++ tests/gpu-test/src/TestFloorGrid.h | 26 +++ tests/gpu-test/src/TestFloorTexture.cpp | 88 +++++++++ tests/gpu-test/src/TestFloorTexture.h | 22 +++ tests/gpu-test/src/main.cpp | 7 +- tests/gpu-test/src/unlit.slf | 28 --- tests/gpu-test/src/unlit.slv | 36 ---- 20 files changed, 1276 insertions(+), 76 deletions(-) create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45Backend.h create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp create mode 100644 libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp create mode 100644 libraries/gpu/src/gpu/null/NullBackend.h create mode 100644 tests/gpu-test/src/TestFbx.cpp create mode 100644 tests/gpu-test/src/TestFbx.h create mode 100644 tests/gpu-test/src/TestFloorGrid.cpp create mode 100644 tests/gpu-test/src/TestFloorGrid.h create mode 100644 tests/gpu-test/src/TestFloorTexture.cpp create mode 100644 tests/gpu-test/src/TestFloorTexture.h delete mode 100644 tests/gpu-test/src/unlit.slf delete mode 100644 tests/gpu-test/src/unlit.slv diff --git a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp index e18b784018..32e063a4c6 100644 --- a/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl/src/gpu/gl/GLBackend.cpp @@ -17,6 +17,7 @@ #include #include "../gl41/GL41Backend.h" +#include "../gl45/GL45Backend.h" #if defined(NSIGHT_FOUND) #include "nvToolsExt.h" @@ -31,25 +32,19 @@ using namespace gpu; using namespace gpu::gl; - static const QString DEBUG_FLAG("HIFI_ENABLE_OPENGL_45"); bool enableOpenGL45 = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); Backend* GLBackend::createBackend() { - -#if 0 // FIXME provide a mechanism to override the backend for testing // Where the gpuContext is initialized and where the TRUE Backend is created and assigned auto version = QOpenGLContextWrapper::currentContextVersion(); GLBackend* result; if (enableOpenGL45 && version >= 0x0405) { - result = new gpu::gl45::GLBackend; + result = new gpu::gl45::GL45Backend(); } else { - result = new gpu::gl41::GLBackend; + result = new gpu::gl41::GL41Backend(); } -#else - GLBackend* result = new gpu::gl41::GL41Backend; -#endif result->initInput(); result->initTransform(); gl::GLTexture::initTextureTransferHelper(); diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp index 3c6109bbdf..478d210535 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendQuery.cpp @@ -16,7 +16,7 @@ using namespace gpu; using namespace gpu::gl41; class GL41Query : public gpu::gl::GLQuery { - using Parent = gpu::gl::GLBuffer; + using Parent = gpu::gl::GLQuery; public: static GLuint allocateQuery() { GLuint result; @@ -25,7 +25,7 @@ public: } GL41Query(const Query& query) - : gl::GLQuery(query, allocateQuery()) { } + : Parent(query, allocateQuery()) { } }; gl::GLQuery* GL41Backend::syncGPUObject(const Query& query) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp new file mode 100644 index 0000000000..bb6ae67233 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -0,0 +1,149 @@ +// +// Created by Sam Gateau on 10/27/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(gpugl45logging, "hifi.gpu.gl45") + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::do_draw(Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 1]._uint; + uint32 startVertex = batch._params[paramOffset + 0]._uint; + + if (isStereo()) { + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); + + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawIndexed(Batch& batch, size_t paramOffset) { + Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numIndices = batch._params[paramOffset + 1]._uint; + uint32 startIndex = batch._params[paramOffset + 0]._uint; + + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { + setupStereoSide(0); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + setupStereoSide(1); + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + + _stats._DSNumTriangles += 2 * numIndices / 3; + _stats._DSNumDrawcalls += 2; + } else { + glDrawElements(mode, numIndices, glType, indexBufferByteOffset); + _stats._DSNumTriangles += numIndices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawInstanced(Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + Primitive primitiveType = (Primitive)batch._params[paramOffset + 3]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; + uint32 numVertices = batch._params[paramOffset + 2]._uint; + uint32 startVertex = batch._params[paramOffset + 1]._uint; + + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + + setupStereoSide(0); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + setupStereoSide(1); + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + + _stats._DSNumTriangles += (trueNumInstances * numVertices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + glDrawArraysInstanced(mode, startVertex, numVertices, numInstances); + _stats._DSNumTriangles += (numInstances * numVertices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + _stats._DSNumAPIDrawcalls++; + + (void) CHECK_GL_ERROR(); +} + +void GL45Backend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) { + GLint numInstances = batch._params[paramOffset + 4]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 3]._uint]; + uint32 numIndices = batch._params[paramOffset + 2]._uint; + uint32 startIndex = batch._params[paramOffset + 1]._uint; + uint32 startInstance = batch._params[paramOffset + 0]._uint; + GLenum glType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + auto typeByteSize = TYPE_SIZE[_input._indexBufferType]; + GLvoid* indexBufferByteOffset = reinterpret_cast(startIndex * typeByteSize + _input._indexBufferOffset); + + if (isStereo()) { + GLint trueNumInstances = 2 * numInstances; + setupStereoSide(0); + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + setupStereoSide(1); + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + _stats._DSNumTriangles += (trueNumInstances * numIndices) / 3; + _stats._DSNumDrawcalls += trueNumInstances; + } else { + glDrawElementsInstancedBaseVertexBaseInstance(mode, numIndices, glType, indexBufferByteOffset, numInstances, 0, startInstance); + _stats._DSNumTriangles += (numInstances * numIndices) / 3; + _stats._DSNumDrawcalls += numInstances; + } + + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) { + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) { + uint commandCount = batch._params[paramOffset + 0]._uint; + GLenum mode = gl::PRIMITIVE_TO_GL[(Primitive)batch._params[paramOffset + 1]._uint]; + GLenum indexType = gl::ELEMENT_TYPE_TO_GL[_input._indexBufferType]; + glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); + _stats._DSNumDrawcalls += commandCount; + _stats._DSNumAPIDrawcalls++; + (void)CHECK_GL_ERROR(); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h new file mode 100644 index 0000000000..d0dfbd0e41 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -0,0 +1,85 @@ +// +// GL45Backend.h +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 10/27/2014. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_45_GL45Backend_h +#define hifi_gpu_45_GL45Backend_h + +#include "../gl/GLBackend.h" +#include "../gl/GLTexture.h" + +namespace gpu { namespace gl45 { + +class GL45Backend : public gl::GLBackend { + using Parent = gl::GLBackend; + // Context Backend static interface required + friend class Context; + +public: + explicit GL45Backend(bool syncCache) : Parent(syncCache) {} + GL45Backend() : Parent() {} + + class GL45Texture : public gpu::gl::GLTexture { + using Parent = gpu::gl::GLTexture; + GLuint allocate(const Texture& texture); + public: + GL45Texture(const Texture& texture, bool transferrable); + GL45Texture(const Texture& texture, GLTexture* original); + + protected: + void transferMip(uint16_t mipLevel, uint8_t face = 0) const; + void allocateStorage() const override; + void updateSize() const override; + void transfer() const override; + void syncSampler() const override; + void generateMips() const override; + void withPreservedTexture(std::function f) const override; + }; + + +protected: + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; + gl::GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; + + GLuint getBufferID(const Buffer& buffer) override; + gl::GLBuffer* syncGPUObject(const Buffer& buffer) override; + + GLuint getTextureID(const TexturePointer& texture, bool needTransfer = true) override; + gl::GLTexture* syncGPUObject(const TexturePointer& texture, bool sync = true) override; + + GLuint getQueryID(const QueryPointer& query) override; + gl::GLQuery* syncGPUObject(const Query& query) override; + + // Draw Stage + void do_draw(Batch& batch, size_t paramOffset) override; + void do_drawIndexed(Batch& batch, size_t paramOffset) override; + void do_drawInstanced(Batch& batch, size_t paramOffset) override; + void do_drawIndexedInstanced(Batch& batch, size_t paramOffset) override; + void do_multiDrawIndirect(Batch& batch, size_t paramOffset) override; + void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) override; + + // Input Stage + void updateInput() override; + + // Synchronize the state cache of this Backend with the actual real state of the GL Context + void transferTransformState(const Batch& batch) const override; + void initTransform() override; + void updateTransform(const Batch& batch); + void resetTransformStage(); + + // Output stage + void do_blit(Batch& batch, size_t paramOffset) override; +}; + +} } + +Q_DECLARE_LOGGING_CATEGORY(gpugl45logging) + + +#endif diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp new file mode 100644 index 0000000000..b7bb04cbfb --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp @@ -0,0 +1,48 @@ +// +// Created by Bradley Austin Davis on 2016/05/15 +// Copyright 2013-2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" +#include "../gl/GLBuffer.h" + +using namespace gpu; +using namespace gpu::gl45; + +class GL45Buffer : public gl::GLBuffer { + using Parent = gpu::gl::GLBuffer; + static GLuint allocate() { + GLuint result; + glCreateBuffers(1, &result); + return result; + } + +public: + GL45Buffer(const Buffer& buffer, GLBuffer* original) : Parent(buffer, allocate()) { + glNamedBufferStorage(_buffer, _size, nullptr, GL_DYNAMIC_STORAGE_BIT); + glCopyNamedBufferSubData(original->_buffer, _buffer, 0, 0, std::min(original->_size, _size)); + Backend::setGPUObject(buffer, this); + } + + void transfer() override { + Size offset; + Size size; + Size currentPage { 0 }; + auto data = _gpuObject.getSysmem().readData(); + while (_gpuObject.getNextTransferBlock(offset, size, currentPage)) { + glNamedBufferSubData(_buffer, (GLintptr)offset, (GLsizeiptr)size, data + offset); + } + (void)CHECK_GL_ERROR(); + _gpuObject._flags &= ~Buffer::DIRTY; + } +}; + +GLuint GL45Backend::getBufferID(const Buffer& buffer) { + return GL45Buffer::getId(buffer); +} + +gl::GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) { + return GL45Buffer::sync(buffer); +} diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp new file mode 100644 index 0000000000..5cefe40448 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -0,0 +1,83 @@ +// +// GL45BackendInput.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::updateInput() { + if (_input._invalidFormat) { + + InputStageState::ActivationCache newActivation; + + // Assign the vertex format required + if (_input._format) { + for (auto& it : _input._format->getAttributes()) { + const Stream::Attribute& attrib = (it).second; + + GLuint slot = attrib._slot; + GLuint count = attrib._element.getLocationScalarCount(); + uint8_t locationCount = attrib._element.getLocationCount(); + GLenum type = gl::ELEMENT_TYPE_TO_GL[attrib._element.getType()]; + GLuint offset = (GLuint)attrib._offset;; + GLboolean isNormalized = attrib._element.isNormalized(); + + GLenum perLocationSize = attrib._element.getLocationSize(); + + for (uint8_t locNum = 0; locNum < locationCount; ++locNum) { + newActivation.set(slot + locNum); + glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize); + glVertexAttribBinding(slot + locNum, attrib._channel); + } + glVertexBindingDivisor(attrib._channel, attrib._frequency); + } + (void) CHECK_GL_ERROR(); + } + + // Manage Activation what was and what is expected now + for (uint32_t i = 0; i < newActivation.size(); i++) { + bool newState = newActivation[i]; + if (newState != _input._attributeActivation[i]) { + if (newState) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + _input._attributeActivation.flip(i); + } + } + (void) CHECK_GL_ERROR(); + + _input._invalidFormat = false; + _stats._ISNumFormatChanges++; + } + + if (_input._invalidBuffers.any()) { + auto numBuffers = _input._buffers.size(); + auto buffer = _input._buffers.data(); + auto vbo = _input._bufferVBOs.data(); + auto offset = _input._bufferOffsets.data(); + auto stride = _input._bufferStrides.data(); + + for (uint32_t bufferNum = 0; bufferNum < numBuffers; bufferNum++) { + if (_input._invalidBuffers.test(bufferNum)) { + glBindVertexBuffer(bufferNum, (*vbo), (GLuint)(*offset), (GLuint)(*stride)); + } + buffer++; + vbo++; + offset++; + stride++; + } + _input._invalidBuffers.reset(); + (void) CHECK_GL_ERROR(); + } +} + diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp new file mode 100644 index 0000000000..7f511be3e8 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp @@ -0,0 +1,145 @@ +// +// GL45BackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" +#include "../gl/GLFramebuffer.h" +#include "../gl/GLTexture.h" + +#include + +namespace gpu { namespace gl45 { + +class GL45Framebuffer : public gl::GLFramebuffer { + using Parent = gl::GLFramebuffer; + static GLuint allocate() { + GLuint result; + glCreateFramebuffers(1, &result); + return result; + } +public: + void update() override { + gl::GLTexture* gltexture = nullptr; + TexturePointer surface; + if (_gpuObject.getColorStamps() != _colorStamps) { + if (_gpuObject.hasColor()) { + _colorBuffers.clear(); + static const GLenum colorAttachments[] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + GL_COLOR_ATTACHMENT8, + GL_COLOR_ATTACHMENT9, + GL_COLOR_ATTACHMENT10, + GL_COLOR_ATTACHMENT11, + GL_COLOR_ATTACHMENT12, + GL_COLOR_ATTACHMENT13, + GL_COLOR_ATTACHMENT14, + GL_COLOR_ATTACHMENT15 }; + + int unit = 0; + for (auto& b : _gpuObject.getRenderBuffers()) { + surface = b._texture; + if (surface) { + gltexture = gl::GLTexture::sync(surface, false); // Grab the gltexture and don't transfer + } else { + gltexture = nullptr; + } + + if (gltexture) { + glNamedFramebufferTexture(_id, colorAttachments[unit], gltexture->_texture, 0); + _colorBuffers.push_back(colorAttachments[unit]); + } else { + glNamedFramebufferTexture(_id, colorAttachments[unit], 0, 0); + } + unit++; + } + } + _colorStamps = _gpuObject.getColorStamps(); + } + + GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT; + if (!_gpuObject.hasStencil()) { + attachement = GL_DEPTH_ATTACHMENT; + } else if (!_gpuObject.hasDepth()) { + attachement = GL_STENCIL_ATTACHMENT; + } + + if (_gpuObject.getDepthStamp() != _depthStamp) { + auto surface = _gpuObject.getDepthStencilBuffer(); + if (_gpuObject.hasDepthStencil() && surface) { + gltexture = gl::GLTexture::sync(surface, false); // Grab the gltexture and don't transfer + } + + if (gltexture) { + glNamedFramebufferTexture(_id, attachement, gltexture->_texture, 0); + } else { + glNamedFramebufferTexture(_id, attachement, 0, 0); + } + _depthStamp = _gpuObject.getDepthStamp(); + } + + + // Last but not least, define where we draw + if (!_colorBuffers.empty()) { + glDrawBuffers((GLsizei)_colorBuffers.size(), _colorBuffers.data()); + } else { + glDrawBuffer(GL_NONE); + } + + // Now check for completness + _status = glCheckNamedFramebufferStatus(_id, GL_DRAW_FRAMEBUFFER); + + // restore the current framebuffer + checkStatus(GL_DRAW_FRAMEBUFFER); + } + + +public: + GL45Framebuffer(const gpu::Framebuffer& framebuffer) + : Parent(framebuffer, allocate()) { } +}; + +gl::GLFramebuffer* GL45Backend::syncGPUObject(const Framebuffer& framebuffer) { + return gl::GLFramebuffer::sync(framebuffer); +} + +GLuint GL45Backend::getFramebufferID(const FramebufferPointer& framebuffer) { + return framebuffer ? gl::GLFramebuffer::getId(*framebuffer) : 0; +} + +void GL45Backend::do_blit(Batch& batch, size_t paramOffset) { + auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); + Vec4i srcvp; + for (auto i = 0; i < 4; ++i) { + srcvp[i] = batch._params[paramOffset + 1 + i]._int; + } + + auto dstframebuffer = batch._framebuffers.get(batch._params[paramOffset + 5]._uint); + Vec4i dstvp; + for (auto i = 0; i < 4; ++i) { + dstvp[i] = batch._params[paramOffset + 6 + i]._int; + } + + // Assign dest framebuffer if not bound already + auto destFbo = getFramebufferID(dstframebuffer); + auto srcFbo = getFramebufferID(srcframebuffer); + glBlitNamedFramebuffer(srcFbo, destFbo, + srcvp.x, srcvp.y, srcvp.z, srcvp.w, + dstvp.x, dstvp.y, dstvp.z, dstvp.w, + GL_COLOR_BUFFER_BIT, GL_LINEAR); + (void) CHECK_GL_ERROR(); +} + +} } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp new file mode 100644 index 0000000000..a7a7c26bed --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp @@ -0,0 +1,38 @@ +// +// GL45BackendQuery.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 7/7/2015. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include "../gl/GLQuery.h" + +namespace gpu { namespace gl45 { + +class GL45Query : public gpu::gl::GLQuery { + using Parent = gpu::gl::GLQuery; +public: + static GLuint allocateQuery() { + GLuint result; + glCreateQueries(GL_TIME_ELAPSED, 1, &result); + return result; + } + + GL45Query(const Query& query) + : Parent(query, allocateQuery()) { } +}; + +gl::GLQuery* GL45Backend::syncGPUObject(const Query& query) { + return GL45Query::sync(query); +} + +GLuint GL45Backend::getQueryID(const QueryPointer& query) { + return GL45Query::getId(query); +} + +} } \ No newline at end of file diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp new file mode 100644 index 0000000000..36fb4bfde3 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -0,0 +1,181 @@ +// +// GL45BackendTexture.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 1/19/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +#include +#include +#include + +#include "../gl/GLTexelFormat.h" + +using namespace gpu; +using namespace gpu::gl45; + +using GLTexelFormat = gl::GLTexelFormat; +using GL45Texture = GL45Backend::GL45Texture; + +GLuint GL45Texture::allocate(const Texture& texture) { + Backend::incrementTextureGPUCount(); + GLuint result; + glCreateTextures(getGLTextureType(texture), 1, &result); + return result; +} + +GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { + return GL45Texture::getId(texture, transfer); +} + +gl::GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) { + return GL45Texture::sync(texture, transfer); +} + +GL45Backend::GL45Texture::GL45Texture(const Texture& texture, bool transferrable) + : gl::GLTexture(texture, allocate(texture), transferrable) {} + +GL45Backend::GL45Texture::GL45Texture(const Texture& texture, GLTexture* original) + : gl::GLTexture(texture, allocate(texture), original) {} + +void GL45Backend::GL45Texture::withPreservedTexture(std::function f) const { + f(); +} + +void GL45Backend::GL45Texture::generateMips() const { + glGenerateTextureMipmap(_id); + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::GL45Texture::allocateStorage() const { + gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat()); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0); + glTextureParameteri(_id, GL_TEXTURE_MAX_LEVEL, _maxMip - _minMip); + if (_gpuObject.getTexelFormat().isCompressed()) { + qFatal("Compressed textures not yet supported"); + } + // Get the dimensions, accounting for the downgrade level + Vec3u dimensions = _gpuObject.evalMipDimensions(_minMip); + glTextureStorage2D(_id, usedMipLevels(), texelFormat.internalFormat, dimensions.x, dimensions.y); + (void)CHECK_GL_ERROR(); +} + +void GL45Backend::GL45Texture::updateSize() const { + setSize(_virtualSize); + if (!_id) { + return; + } + + if (_gpuObject.getTexelFormat().isCompressed()) { + qFatal("Compressed textures not yet supported"); + } +} + +// Move content bits from the CPU to the GPU for a given mip / face +void GL45Backend::GL45Texture::transferMip(uint16_t mipLevel, uint8_t face) const { + auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); + gl::GLTexelFormat texelFormat = gl::GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); + auto size = _gpuObject.evalMipDimensions(mipLevel); + if (GL_TEXTURE_2D == _target) { + glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); + } else if (GL_TEXTURE_CUBE_MAP == _target) { + glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); + } else { + Q_ASSERT(false); + } + (void)CHECK_GL_ERROR(); +} + +// This should never happen on the main thread +// Move content bits from the CPU to the GPU +void GL45Backend::GL45Texture::transfer() const { + PROFILE_RANGE(__FUNCTION__); + //qDebug() << "Transferring texture: " << _privateTexture; + // Need to update the content of the GPU object from the source sysmem of the texture + if (_contentStamp >= _gpuObject.getDataStamp()) { + return; + } + + if (_downsampleSource._texture) { + GLuint fbo { 0 }; + glCreateFramebuffers(1, &fbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); + // Find the distance between the old min mip and the new one + uint16 mipOffset = _minMip - _downsampleSource._minMip; + for (uint16 i = _minMip; i <= _maxMip; ++i) { + uint16 targetMip = i - _minMip; + uint16 sourceMip = targetMip + mipOffset; + Vec3u dimensions = _gpuObject.evalMipDimensions(i); + for (GLenum target : getFaceTargets(_target)) { + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, _downsampleSource._texture, sourceMip); + (void)CHECK_GL_ERROR(); + glCopyTextureSubImage2D(_id, targetMip, 0, 0, 0, 0, dimensions.x, dimensions.y); + (void)CHECK_GL_ERROR(); + } + } + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &fbo); + } else { + // GO through the process of allocating the correct storage and/or update the content + switch (_gpuObject.getType()) { + case Texture::TEX_2D: + { + for (uint16_t i = _minMip; i <= _maxMip; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i)) { + transferMip(i); + } + } + } + break; + + case Texture::TEX_CUBE: + // transfer pixels from each faces + for (uint8_t f = 0; f < CUBE_NUM_FACES; f++) { + for (uint16_t i = 0; i < Sampler::MAX_MIP_LEVEL; ++i) { + if (_gpuObject.isStoredMipFaceAvailable(i, f)) { + transferMip(i, f); + } + } + } + break; + + default: + qCWarning(gpugl45logging) << __FUNCTION__ << " case for Texture Type " << _gpuObject.getType() << " not supported"; + break; + } + } + if (_gpuObject.isAutogenerateMips()) { + glGenerateTextureMipmap(_id); + (void)CHECK_GL_ERROR(); + } +} + +void GL45Backend::GL45Texture::syncSampler() const { + const Sampler& sampler = _gpuObject.getSampler(); + + const auto& fm = FILTER_MODES[sampler.getFilter()]; + glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); + glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter); + + if (sampler.doComparison()) { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, gl::COMPARISON_TO_GL[sampler.getComparisonFunction()]); + } else { + glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]); + glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); + glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); + glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset()); + glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip()); + glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); + glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy()); +} + diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp new file mode 100644 index 0000000000..fd49729164 --- /dev/null +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp @@ -0,0 +1,71 @@ +// +// GL45BackendTransform.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 3/8/2015. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "GL45Backend.h" + +using namespace gpu; +using namespace gpu::gl45; + +void GL45Backend::initTransform() { + GLuint transformBuffers[3]; + glCreateBuffers(3, transformBuffers); + _transform._objectBuffer = transformBuffers[0]; + _transform._cameraBuffer = transformBuffers[1]; + _transform._drawCallInfoBuffer = transformBuffers[2]; + glCreateTextures(1, GL_TEXTURE_2D, &_transform._objectBufferTexture); + size_t cameraSize = sizeof(TransformStageState::CameraBufferElement); + while (_transform._cameraUboSize < cameraSize) { + _transform._cameraUboSize += _uboAlignment; + } +} + +void GL45Backend::transferTransformState(const Batch& batch) const { + // FIXME not thread safe + static std::vector bufferData; + if (!_transform._cameras.empty()) { + bufferData.resize(_transform._cameraUboSize * _transform._cameras.size()); + for (size_t i = 0; i < _transform._cameras.size(); ++i) { + memcpy(bufferData.data() + (_transform._cameraUboSize * i), &_transform._cameras[i], sizeof(TransformStageState::CameraBufferElement)); + } + glNamedBufferData(_transform._cameraBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + + if (!batch._objects.empty()) { + auto byteSize = batch._objects.size() * sizeof(Batch::TransformObject); + bufferData.resize(byteSize); + memcpy(bufferData.data(), batch._objects.data(), byteSize); + glNamedBufferData(_transform._objectBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + + if (!batch._namedData.empty()) { + bufferData.clear(); + for (auto& data : batch._namedData) { + auto currentSize = bufferData.size(); + auto bytesToCopy = data.second.drawCallInfos.size() * sizeof(Batch::DrawCallInfo); + bufferData.resize(currentSize + bytesToCopy); + memcpy(bufferData.data() + currentSize, data.second.drawCallInfos.data(), bytesToCopy); + _transform._drawCallInfoOffsets[data.first] = (GLvoid*)currentSize; + } + glNamedBufferData(_transform._drawCallInfoBuffer, bufferData.size(), bufferData.data(), GL_STREAM_DRAW); + } + +#ifdef GPU_SSBO_DRAW_CALL_INFO + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._objectBuffer); +#else + glActiveTexture(GL_TEXTURE0 + TRANSFORM_OBJECT_SLOT); + glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer); +#endif + + CHECK_GL_ERROR(); + + // Make sure the current Camera offset is unknown before render Draw + _transform._currentCameraOffset = INVALID_OFFSET; +} diff --git a/libraries/gpu/src/gpu/null/NullBackend.h b/libraries/gpu/src/gpu/null/NullBackend.h new file mode 100644 index 0000000000..097cee27e7 --- /dev/null +++ b/libraries/gpu/src/gpu/null/NullBackend.h @@ -0,0 +1,54 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_gpu_Null_Backend_h +#define hifi_gpu_Null_Backend_h + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../Context.h" + +namespace gpu { namespace null { + +class Backend : public gpu::Backend { + using Parent = gpu::Backend; + // Context Backend static interface required + friend class gpu::Context; + static void init() {} + static gpu::Backend* createBackend() { return new Backend(); } + static bool makeProgram(Shader& shader, const Shader::BindingSet& slotBindings) { return true; } + +protected: + explicit Backend(bool syncCache) : Parent() { } + Backend() : Parent() { } +public: + ~Backend() { } + + void render(Batch& batch) final { } + + // This call synchronize the Full Backend cache with the current GLState + // THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync + // the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls + // Let's try to avoid to do that as much as possible! + void syncCache() final { } + + // This is the ugly "download the pixels to sysmem for taking a snapshot" + // Just avoid using it, it's ugly and will break performances + virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final { } +}; + +} } + +#endif diff --git a/tests/gpu-test/src/TestFbx.cpp b/tests/gpu-test/src/TestFbx.cpp new file mode 100644 index 0000000000..cea356e125 --- /dev/null +++ b/tests/gpu-test/src/TestFbx.cpp @@ -0,0 +1,187 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFbx.h" + +#include + +#include + +#include + +struct MyVertex { + vec3 position; + vec2 texCoords; + vec3 normal; + uint32_t color; + + static gpu::Stream::FormatPointer getVertexFormat() { + 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::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; + static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::NUINT8, gpu::RGBA }; + gpu::Stream::FormatPointer vertexFormat { std::make_shared() }; + vertexFormat->setAttribute(gpu::Stream::POSITION, 0, POSITION_ELEMENT, offsetof(MyVertex, position)); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, TEXTURE_ELEMENT, offsetof(MyVertex, texCoords)); + vertexFormat->setAttribute(gpu::Stream::COLOR, 0, COLOR_ELEMENT, offsetof(MyVertex, color)); + vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, NORMAL_ELEMENT, offsetof(MyVertex, normal)); + return vertexFormat; + } + +}; + +struct Part { + size_t baseVertex; + size_t baseIndex; + size_t materialId; +}; + +struct DrawElementsIndirectCommand { + uint count { 0 }; + uint instanceCount { 1 }; + uint firstIndex { 0 }; + uint baseVertex { 0 }; + uint baseInstance { 0 }; +}; + + +class FileDownloader : public QObject { + Q_OBJECT +public: + explicit FileDownloader(QUrl imageUrl, QObject *parent = 0) : QObject(parent) { + connect(&m_WebCtrl, SIGNAL(finished(QNetworkReply*)), this, SLOT(fileDownloaded(QNetworkReply*))); + QNetworkRequest request(imageUrl); + m_WebCtrl.get(request); + } + + virtual ~FileDownloader() {} + + const QByteArray& downloadedData() const { + return m_DownloadedData; + } + +signals: + void downloaded(); + +private slots: + void fileDownloaded(QNetworkReply* pReply) { + m_DownloadedData = pReply->readAll(); + pReply->deleteLater(); + emit downloaded(); + } + +private: + QNetworkAccessManager m_WebCtrl; + QByteArray m_DownloadedData; +}; + + +static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/models/tardis/console.fbx"); +static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -1.5f, 0)) * glm::scale(mat4(), vec3(0.01f)); +//static const QUrl TEST_ASSET = QString("https://s3.amazonaws.com/DreamingContent/assets/simple/SimpleMilitary/Models/Vehicles/tank_02_c.fbx"); +//static const mat4 TEST_ASSET_TRANSFORM = glm::translate(mat4(), vec3(0, -0.5f, 0)) * glm::scale(mat4(), vec3(0.1f)); + +TestFbx::TestFbx(const render::ShapePlumberPointer& shapePlumber) : _shapePlumber(shapePlumber) { + FileDownloader* downloader = new FileDownloader(TEST_ASSET, qApp); + QObject::connect(downloader, &FileDownloader::downloaded, [this, downloader] { + parseFbx(downloader->downloadedData()); + }); +} + +bool TestFbx::isReady() const { + return _partCount != 0; +} + +void TestFbx::parseFbx(const QByteArray& fbxData) { + QVariantHash mapping; + FBXGeometry* fbx = readFBX(fbxData, mapping); + size_t totalVertexCount = 0; + size_t totalIndexCount = 0; + size_t totalPartCount = 0; + size_t highestIndex = 0; + for (const auto& mesh : fbx->meshes) { + size_t vertexCount = mesh.vertices.size(); + totalVertexCount += mesh.vertices.size(); + highestIndex = std::max(highestIndex, vertexCount); + totalPartCount += mesh.parts.size(); + for (const auto& part : mesh.parts) { + totalIndexCount += part.quadTrianglesIndices.size(); + totalIndexCount += part.triangleIndices.size(); + } + } + size_t baseVertex = 0; + std::vector vertices; + vertices.reserve(totalVertexCount); + std::vector indices; + indices.reserve(totalIndexCount); + std::vector parts; + parts.reserve(totalPartCount); + _partCount = totalPartCount; + for (const auto& mesh : fbx->meshes) { + baseVertex = vertices.size(); + + vec3 color; + for (const auto& part : mesh.parts) { + DrawElementsIndirectCommand partIndirect; + partIndirect.baseVertex = (uint)baseVertex; + partIndirect.firstIndex = (uint)indices.size(); + partIndirect.baseInstance = (uint)parts.size(); + _partTransforms.push_back(mesh.modelTransform); + auto material = fbx->materials[part.materialID]; + color = material.diffuseColor; + for (auto index : part.quadTrianglesIndices) { + indices.push_back(index); + } + for (auto index : part.triangleIndices) { + indices.push_back(index); + } + size_t triangles = (indices.size() - partIndirect.firstIndex); + Q_ASSERT(0 == (triangles % 3)); + //triangles /= 3; + partIndirect.count = (uint)triangles; + parts.push_back(partIndirect); + } + + size_t vertexCount = mesh.vertices.size(); + for (size_t i = 0; i < vertexCount; ++i) { + MyVertex vertex; + vertex.position = mesh.vertices[(int)i]; + vec3 n = mesh.normals[(int)i]; + vertex.normal = n; + vertex.texCoords = mesh.texCoords[(int)i]; + vertex.color = toCompactColor(vec4(color, 1)); + vertices.push_back(vertex); + } + } + + _vertexBuffer->append(vertices); + _indexBuffer->append(indices); + _indirectBuffer->append(parts); + delete fbx; +} + +void TestFbx::renderTest(size_t testId, RenderArgs* args) { + gpu::Batch& batch = *(args->_batch); + //pipeline->pipeline + if (_partCount) { + for (size_t i = 0; i < _partCount; ++i) { + batch.setModelTransform(TEST_ASSET_TRANSFORM * _partTransforms[i]); + batch.setupNamedCalls(__FUNCTION__, [this](gpu::Batch& batch, gpu::Batch::NamedBatchData&) { + RenderArgs args; args._batch = &batch; + _shapePlumber->pickPipeline(&args, render::ShapeKey()); + batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(MyVertex)); + batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0); + batch.setInputFormat(MyVertex::getVertexFormat()); + batch.setIndirectBuffer(_indirectBuffer, 0); + batch.multiDrawIndexedIndirect((uint)_partCount, gpu::TRIANGLES); + }); + } + } +} + +#include "TestFbx.moc" diff --git a/tests/gpu-test/src/TestFbx.h b/tests/gpu-test/src/TestFbx.h new file mode 100644 index 0000000000..1f3c0bb50e --- /dev/null +++ b/tests/gpu-test/src/TestFbx.h @@ -0,0 +1,35 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "TestHelpers.h" + +#include + +class FBXGeometry; + +class TestFbx : public GpuTestBase { + size_t _partCount { 0 }; + model::Material _material; + render::ShapeKey _shapeKey; + std::vector _partTransforms; + render::ShapePlumberPointer _shapePlumber; + gpu::Stream::FormatPointer _vertexFormat { std::make_shared() }; + gpu::BufferPointer _vertexBuffer { std::make_shared() }; + gpu::BufferPointer _indexBuffer { std::make_shared() }; + gpu::BufferPointer _indirectBuffer { std::make_shared() }; +public: + TestFbx(const render::ShapePlumberPointer& shapePlumber); + bool isReady() const override; + void renderTest(size_t test, RenderArgs* args) override; + +private: + void parseFbx(const QByteArray& fbxData); +}; + + diff --git a/tests/gpu-test/src/TestFloorGrid.cpp b/tests/gpu-test/src/TestFloorGrid.cpp new file mode 100644 index 0000000000..a24b4778d4 --- /dev/null +++ b/tests/gpu-test/src/TestFloorGrid.cpp @@ -0,0 +1,54 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFloorGrid.h" + + +TestFloorGrid::TestFloorGrid() { + 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); + } + } + } + +} + +void TestFloorGrid::renderTest(size_t testId, RenderArgs* args) { + //gpu::Batch& batch = *(args->_batch); + //auto pipeline = geometryCache->getSimplePipeline(); + //for (auto& transform : transforms) { + // batch.setModelTransform(transform); + // batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + // batch.setPipeline(_pipeline); + // geometryCache->renderWireShapeInstances(batch, GeometryCache::Line, data.count(), colorBuffer); + // }); + //} +} diff --git a/tests/gpu-test/src/TestFloorGrid.h b/tests/gpu-test/src/TestFloorGrid.h new file mode 100644 index 0000000000..566c8f0968 --- /dev/null +++ b/tests/gpu-test/src/TestFloorGrid.h @@ -0,0 +1,26 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once + +#include +#include +#include + +#include +#include + +#include "TestHelpers.h" + +class TestFloorGrid : public GpuTestBase { +public: + TestFloorGrid(); + void renderTest(size_t testId, RenderArgs* args) override; +}; + + diff --git a/tests/gpu-test/src/TestFloorTexture.cpp b/tests/gpu-test/src/TestFloorTexture.cpp new file mode 100644 index 0000000000..884be5ec30 --- /dev/null +++ b/tests/gpu-test/src/TestFloorTexture.cpp @@ -0,0 +1,88 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TestFloorTexture.h" + +struct Vertex { + vec4 position; + vec4 texture; + vec4 normal; + vec4 color; +}; +static const uint TEXTURE_OFFSET = offsetof(Vertex, texture); +static const uint NORMAL_OFFSET = offsetof(Vertex, normal); +static const uint POSITION_OFFSET = offsetof(Vertex, position); +static const uint COLOR_OFFSET = offsetof(Vertex, color); +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::Element NORMAL_ELEMENT { gpu::VEC3, gpu::FLOAT, gpu::XYZ }; +static const gpu::Element COLOR_ELEMENT { gpu::VEC4, gpu::FLOAT, gpu::RGBA }; + +FloorTextureTest::FloorTextureTest() { + auto geometryCache = DependencyManager::get(); + std::vector vertices; + const int MINX = -1000; + const int MAXX = 1000; + + vertices.push_back({ + vec4(MAXX, 0, MAXX, 1), + vec4(MAXX, MAXX, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MAXX, 0, MINX, 1), + vec4(MAXX, 0, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MINX, 0, MINX, 1), + vec4(0, 0, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertices.push_back({ + vec4(MINX, 0, MAXX, 1), + vec4(0, MAXX, 0, 0), + vec4(0, 1, 0, 1), + vec4(1), + }); + + vertexBuffer->append(vertices); + indexBuffer->append(std::vector({ 0, 1, 2, 2, 3, 0 })); + 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"); + vertexFormat->setAttribute(gpu::Stream::POSITION, 0, POSITION_ELEMENT, POSITION_OFFSET); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, TEXTURE_ELEMENT, TEXTURE_OFFSET); + vertexFormat->setAttribute(gpu::Stream::COLOR, 0, COLOR_ELEMENT, COLOR_OFFSET); + vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, NORMAL_ELEMENT, NORMAL_OFFSET); +} + +void FloorTextureTest::renderTest(size_t testId, RenderArgs* args) { + gpu::Batch& batch = *(args->_batch); + auto geometryCache = DependencyManager::get(); + static auto start = usecTimestampNow(); + auto now = usecTimestampNow(); + if ((now - start) > USECS_PER_SECOND * 1) { + start = now; + texture->incremementMinMip(); + } + + geometryCache->bindSimpleProgram(batch, true, true, true); + batch.setInputBuffer(0, vertexBuffer, 0, sizeof(Vertex)); + batch.setInputFormat(vertexFormat); + batch.setIndexBuffer(gpu::UINT16, indexBuffer, 0); + batch.setResourceTexture(0, texture); + batch.setModelTransform(glm::translate(glm::mat4(), vec3(0, -0.1, 0))); + batch.drawIndexed(gpu::TRIANGLES, 6, 0); +} diff --git a/tests/gpu-test/src/TestFloorTexture.h b/tests/gpu-test/src/TestFloorTexture.h new file mode 100644 index 0000000000..99eaf902b8 --- /dev/null +++ b/tests/gpu-test/src/TestFloorTexture.h @@ -0,0 +1,22 @@ +// +// Created by Bradley Austin Davis on 2016/05/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#pragma once + +#include "TestHelpers.h" + +class FloorTextureTest : public GpuTestBase { + gpu::BufferPointer vertexBuffer { std::make_shared() }; + gpu::BufferPointer indexBuffer { std::make_shared() }; + gpu::Stream::FormatPointer vertexFormat { std::make_shared() }; + gpu::TexturePointer texture; +public: + FloorTextureTest(); + void renderTest(size_t testId, RenderArgs* args) override; +}; + + diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index e672fe3c86..0f06546327 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -62,6 +62,9 @@ #include #include "TestWindow.h" +#include "TestFbx.h" +#include "TestFloorGrid.h" +#include "TestFloorTexture.h" #include "TestInstancedShapes.h" #include "TestShapes.h" @@ -90,8 +93,8 @@ class MyTestWindow : public TestWindow { #endif updateCamera(); _testBuilders = TestBuilders({ - //[this] { return new TestFbx(_shapePlumber); }, - [] { return new TestShapes(); }, + [this] { return new TestFbx(_shapePlumber); }, + [] { return new TestInstancedShapes(); }, }); } diff --git a/tests/gpu-test/src/unlit.slf b/tests/gpu-test/src/unlit.slf deleted file mode 100644 index f88fcb510b..0000000000 --- a/tests/gpu-test/src/unlit.slf +++ /dev/null @@ -1,28 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple.frag -// fragment shader -// -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include DeferredBufferWrite.slh@> -<@include model/Material.slh@> - -// the interpolated normal -in vec3 _normal; -in vec3 _color; - -void main(void) { - packDeferredFragment( - normalize(_normal.xyz), - 1.0, - _color.rgb, - DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, DEFAULT_OCCLUSION); -} diff --git a/tests/gpu-test/src/unlit.slv b/tests/gpu-test/src/unlit.slv deleted file mode 100644 index d51d817429..0000000000 --- a/tests/gpu-test/src/unlit.slv +++ /dev/null @@ -1,36 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple.vert -// vertex shader -// -// Created by Andrzej Kapolka on 9/15/14. -// Copyright 2014 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -<@include gpu/Inputs.slh@> - -<@include gpu/Transform.slh@> - -<$declareStandardTransform()$> - -// the interpolated normal -out vec3 _normal; -out vec3 _color; -out vec2 _texCoord0; - -void main(void) { - _color = inColor.rgb; - _texCoord0 = inTexCoord0.st; - - // standard transform - TransformCamera cam = getTransformCamera(); - TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> - <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> - _normal = vec3(0.0, 0.0, 1.0); -} \ No newline at end of file