mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Adding GL 4.5 backend
This commit is contained in:
parent
34faf45a5d
commit
b16812aa4d
20 changed files with 1276 additions and 76 deletions
|
@ -17,6 +17,7 @@
|
|||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#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();
|
||||
|
|
|
@ -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) {
|
||||
|
|
149
libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp
Normal file
149
libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp
Normal file
|
@ -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 <mutex>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
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<GLvoid*>(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<GLvoid*>(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<GLvoid*>(_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<GLvoid*>(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride);
|
||||
_stats._DSNumDrawcalls += commandCount;
|
||||
_stats._DSNumAPIDrawcalls++;
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
85
libraries/gpu-gl/src/gpu/gl45/GL45Backend.h
Normal file
85
libraries/gpu-gl/src/gpu/gl45/GL45Backend.h
Normal file
|
@ -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<void()> 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
|
48
libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp
Normal file
48
libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp
Normal file
|
@ -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<GL45Buffer>(buffer);
|
||||
}
|
||||
|
||||
gl::GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) {
|
||||
return GL45Buffer::sync<GL45Buffer>(buffer);
|
||||
}
|
83
libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp
Normal file
83
libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
145
libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp
Normal file
145
libraries/gpu-gl/src/gpu/gl45/GL45BackendOutput.cpp
Normal file
|
@ -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 <QtGui/QImage>
|
||||
|
||||
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<GL45Backend::GL45Texture>(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<GL45Backend::GL45Texture>(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<GL45Framebuffer>(framebuffer);
|
||||
}
|
||||
|
||||
GLuint GL45Backend::getFramebufferID(const FramebufferPointer& framebuffer) {
|
||||
return framebuffer ? gl::GLFramebuffer::getId<GL45Framebuffer>(*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();
|
||||
}
|
||||
|
||||
} }
|
38
libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp
Normal file
38
libraries/gpu-gl/src/gpu/gl45/GL45BackendQuery.cpp
Normal file
|
@ -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<GL45Query>(query);
|
||||
}
|
||||
|
||||
GLuint GL45Backend::getQueryID(const QueryPointer& query) {
|
||||
return GL45Query::getId<GL45Query>(query);
|
||||
}
|
||||
|
||||
} }
|
181
libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp
Normal file
181
libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp
Normal file
|
@ -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 <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#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<GL45Texture>(texture, transfer);
|
||||
}
|
||||
|
||||
gl::GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texture, bool transfer) {
|
||||
return GL45Texture::sync<GL45Texture>(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<void()> 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());
|
||||
}
|
||||
|
71
libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp
Normal file
71
libraries/gpu-gl/src/gpu/gl45/GL45BackendTransform.cpp
Normal file
|
@ -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<uint8_t> 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;
|
||||
}
|
54
libraries/gpu/src/gpu/null/NullBackend.h
Normal file
54
libraries/gpu/src/gpu/null/NullBackend.h
Normal file
|
@ -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 <assert.h>
|
||||
#include <functional>
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
#include <list>
|
||||
#include <array>
|
||||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#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
|
187
tests/gpu-test/src/TestFbx.cpp
Normal file
187
tests/gpu-test/src/TestFbx.cpp
Normal file
|
@ -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 <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
|
||||
#include <FBXReader.h>
|
||||
|
||||
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<gpu::Stream::Format>() };
|
||||
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<MyVertex> vertices;
|
||||
vertices.reserve(totalVertexCount);
|
||||
std::vector<uint16_t> indices;
|
||||
indices.reserve(totalIndexCount);
|
||||
std::vector<DrawElementsIndirectCommand> 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"
|
35
tests/gpu-test/src/TestFbx.h
Normal file
35
tests/gpu-test/src/TestFbx.h
Normal file
|
@ -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 <render/ShapePipeline.h>
|
||||
|
||||
class FBXGeometry;
|
||||
|
||||
class TestFbx : public GpuTestBase {
|
||||
size_t _partCount { 0 };
|
||||
model::Material _material;
|
||||
render::ShapeKey _shapeKey;
|
||||
std::vector<mat4> _partTransforms;
|
||||
render::ShapePlumberPointer _shapePlumber;
|
||||
gpu::Stream::FormatPointer _vertexFormat { std::make_shared<gpu::Stream::Format>() };
|
||||
gpu::BufferPointer _vertexBuffer { std::make_shared<gpu::Buffer>() };
|
||||
gpu::BufferPointer _indexBuffer { std::make_shared<gpu::Buffer>() };
|
||||
gpu::BufferPointer _indirectBuffer { std::make_shared<gpu::Buffer>() };
|
||||
public:
|
||||
TestFbx(const render::ShapePlumberPointer& shapePlumber);
|
||||
bool isReady() const override;
|
||||
void renderTest(size_t test, RenderArgs* args) override;
|
||||
|
||||
private:
|
||||
void parseFbx(const QByteArray& fbxData);
|
||||
};
|
||||
|
||||
|
54
tests/gpu-test/src/TestFloorGrid.cpp
Normal file
54
tests/gpu-test/src/TestFloorGrid.cpp
Normal file
|
@ -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<GeometryCache>();
|
||||
// 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<glm::mat4> transforms;
|
||||
static gpu::BufferPointer colorBuffer;
|
||||
if (!transforms.empty()) {
|
||||
transforms.reserve(200);
|
||||
colorBuffer = std::make_shared<gpu::Buffer>();
|
||||
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);
|
||||
// });
|
||||
//}
|
||||
}
|
26
tests/gpu-test/src/TestFloorGrid.h
Normal file
26
tests/gpu-test/src/TestFloorGrid.h
Normal file
|
@ -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 <vector>
|
||||
#include <GLMHelpers.h>
|
||||
#include <Transform.h>
|
||||
|
||||
#include <gpu/Resource.h>
|
||||
#include <gpu/Stream.h>
|
||||
|
||||
#include "TestHelpers.h"
|
||||
|
||||
class TestFloorGrid : public GpuTestBase {
|
||||
public:
|
||||
TestFloorGrid();
|
||||
void renderTest(size_t testId, RenderArgs* args) override;
|
||||
};
|
||||
|
||||
|
88
tests/gpu-test/src/TestFloorTexture.cpp
Normal file
88
tests/gpu-test/src/TestFloorTexture.cpp
Normal file
|
@ -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<GeometryCache>();
|
||||
std::vector<Vertex> 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<uint16_t>({ 0, 1, 2, 2, 3, 0 }));
|
||||
texture = DependencyManager::get<TextureCache>()->getImageTexture("C:/Users/bdavis/Git/openvr/samples/bin/cube_texture.png");
|
||||
//texture = DependencyManager::get<TextureCache>()->getImageTexture("H:/test.png");
|
||||
//texture = DependencyManager::get<TextureCache>()->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<GeometryCache>();
|
||||
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);
|
||||
}
|
22
tests/gpu-test/src/TestFloorTexture.h
Normal file
22
tests/gpu-test/src/TestFloorTexture.h
Normal file
|
@ -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::Buffer>() };
|
||||
gpu::BufferPointer indexBuffer { std::make_shared<gpu::Buffer>() };
|
||||
gpu::Stream::FormatPointer vertexFormat { std::make_shared<gpu::Stream::Format>() };
|
||||
gpu::TexturePointer texture;
|
||||
public:
|
||||
FloorTextureTest();
|
||||
void renderTest(size_t testId, RenderArgs* args) override;
|
||||
};
|
||||
|
||||
|
|
@ -62,6 +62,9 @@
|
|||
#include <render/CullTask.h>
|
||||
|
||||
#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(); },
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue