diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 7f36797374..aee6f3bdf4 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -34,6 +34,7 @@ typedef glm::mat3 Mat3; typedef glm::vec4 Vec4; typedef glm::vec3 Vec3; typedef glm::vec2 Vec2; +typedef glm::ivec2 Vec2i; // Description of a scalar type enum Type { diff --git a/libraries/gpu/src/gpu/Framebuffer.cpp b/libraries/gpu/src/gpu/Framebuffer.cpp new file mode 100755 index 0000000000..597a31788e --- /dev/null +++ b/libraries/gpu/src/gpu/Framebuffer.cpp @@ -0,0 +1,267 @@ +// +// Framebuffer.cpp +// libraries/gpu/src/gpu +// +// Created by Sam Gateau on 4/12/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 "Framebuffer.h" +#include +#include + +using namespace gpu; + +Framebuffer::Framebuffer() +{ +} + +Framebuffer::~Framebuffer() +{ +} + +Framebuffer* Framebuffer::create() { + auto framebuffer = new Framebuffer(); + framebuffer->_renderBuffers.resize(MAX_NUM_RENDER_BUFFERS); + framebuffer->_renderBuffersSubresource.resize(MAX_NUM_RENDER_BUFFERS, 0); + return framebuffer; +} + +Framebuffer* Framebuffer::create( const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 numSamples) { + auto framebuffer = Framebuffer::create(); + + auto colorTexture = TexturePointer(Texture::create2D(colorBufferFormat, width, height)); + auto depthTexture = TexturePointer(Texture::create2D(depthStencilBufferFormat, width, height)); + + framebuffer->setRenderBuffer(0, colorTexture); + framebuffer->setDepthStencilBuffer(depthTexture); + + return framebuffer; +} + + +bool Framebuffer::isSwapchain() const { + return _swapchain != 0; +} + +uint32 Framebuffer::getFrameCount() const { + if (_swapchain) { + return _swapchain->getFrameCount(); + } else { + return _frameCount; + } +} + +bool Framebuffer::isEmpty() const { + return (_buffersMask == 0); +} + +bool Framebuffer::validateTargetCompatibility(const Texture& texture, uint32 subresource) const { + if (texture.getType() == Texture::TEX_1D) { + return false; + } + + if (isEmpty()) { + return true; + } else { + if ((texture.getWidth() == getWidth()) && + (texture.getHeight() == getHeight()) && + (texture.getNumSamples() == getNumSamples())) { + return true; + } else { + return false; + } + } +} + +void Framebuffer::updateSize(const TexturePointer& texture) { + if (!isEmpty()) { + return; + } + + if (texture) { + _width = texture->getWidth(); + _height = texture->getHeight(); + _numSamples = texture->getNumSamples(); + } else { + _width = _height = _numSamples = 0; + } +} + +void Framebuffer::resize(uint16 width, uint16 height, uint16 numSamples) { + if (width && height && numSamples && !isEmpty() && !isSwapchain()) { + if ((width != _width) || (height != _height) || (numSamples != _numSamples)) { + for (uint32 i = 0; i < _renderBuffers.size(); ++i) { + if (_renderBuffers[i]) { + _renderBuffers[i]->resize2D(width, height, numSamples); + _numSamples = _renderBuffers[i]->getNumSamples(); + } + } + + if (_depthStencilBuffer) { + _depthStencilBuffer->resize2D(width, height, numSamples); + _numSamples = _depthStencilBuffer->getNumSamples(); + } + + _width = width; + _height = height; + // _numSamples = numSamples; + } + } +} + +uint16 Framebuffer::getWidth() const { + if (isSwapchain()) { + return getSwapchain()->getWidth(); + } else { + return _width; + } +} + +uint16 Framebuffer::getHeight() const { + if (isSwapchain()) { + return getSwapchain()->getHeight(); + } else { + return _height; + } +} + +uint16 Framebuffer::getNumSamples() const { + if (isSwapchain()) { + return getSwapchain()->getNumSamples(); + } else { + return _numSamples; + } +} + +// Render buffers +int Framebuffer::setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource) { + if (isSwapchain()) { + return -1; + } + + // Check for the slot + if (slot >= getMaxNumRenderBuffers()) { + return -1; + } + + // Check for the compatibility of size + if (texture) { + if (!validateTargetCompatibility(*texture, subresource)) { + return -1; + } + } + + // everything works, assign + // dereference the previously used buffer if exists + if (_renderBuffers[slot]) { + _renderBuffers[slot].reset(); + _renderBuffersSubresource[slot] = 0; + } + + updateSize(texture); + + // assign the new one + _renderBuffers[slot] = texture; + + // Assign the subresource + _renderBuffersSubresource[slot] = subresource; + + // update the mask + int mask = (1< + +namespace gpu { + +typedef Element Format; + +class Viewport { +public: + int32 width = 1; + int32 height = 1; + int32 top = 0; + int32 left = 0; + float zmin = 0.f; + float zmax = 1.f; + + Viewport() {} + Viewport(int32 w, int32 h, int32 t = 0, int32 l = 0, float zin = 0.f, float zax = 1.f): + width(w), + height(h), + top(t), + left(l), + zmin(zin), + zmax(zax) + {} + Viewport(const Vec2i& wh, const Vec2i& tl = Vec2i(0), const Vec2& zrange = Vec2(0.f, 1.f)): + width(wh.x), + height(wh.y), + top(tl.x), + left(tl.y), + zmin(zrange.x), + zmax(zrange.y) + {} + ~Viewport() {} +}; + +class Swapchain { +public: + // Properties + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + uint16 getNumSamples() const { return _numSamples; } + + bool hasDepthStencil() const { return _hasDepthStencil; } + bool isFullscreen() const { return _isFullscreen; } + + uint32 getSwapInterval() const { return _swapInterval; } + + bool isStereo() const { return _isStereo; } + + uint32 getFrameCount() const { return _frameCount; } + + // Pure interface + void setSwapInterval(uint32 interval); + + void resize(uint16 width, uint16 height); + void setFullscreen(bool fullscreen); + + Swapchain() {} + Swapchain(const Swapchain& swapchain) {} + virtual ~Swapchain() {} + +protected: + mutable uint32 _frameCount = 0; + + Format _colorFormat; + uint16 _width = 1; + uint16 _height = 1; + uint16 _numSamples = 1; + uint16 _swapInterval = 0; + + bool _hasDepthStencil = false; + bool _isFullscreen = false; + bool _isStereo = false; + + // Non exposed + + friend class Framebuffer; +}; +typedef std::shared_ptr SwapchainPointer; + + +class Framebuffer { +public: + enum BufferMask { + BUFFER_COLOR0 = 1, + BUFFER_COLOR1 = 2, + BUFFER_COLOR2 = 4, + BUFFER_COLOR3 = 8, + BUFFER_COLOR4 = 16, + BUFFER_COLOR5 = 32, + BUFFER_COLOR6 = 64, + BUFFER_COLOR7 = 128, + BUFFER_COLORS = 0x000000FF, + + BUFFER_DEPTH = 0x40000000, + BUFFER_STENCIL = 0x80000000, + BUFFER_DEPTHSTENCIL = 0xC0000000, + }; + + ~Framebuffer(); + + static Framebuffer* create(const SwapchainPointer& swapchain); + static Framebuffer* create(); + static Framebuffer* create(const Format& colorBufferFormat, const Format& depthStencilBufferFormat, uint16 width, uint16 height, uint16 samples ); + + bool isSwapchain() const; + SwapchainPointer getSwapchain() const { return _swapchain; } + + uint32 getFrameCount() const; + + // Render buffers + int32 setRenderBuffer(uint32 slot, const TexturePointer& texture, uint32 subresource = 0); + void removeRenderBuffers(); + uint32 getNumRenderBuffers() const; + + TexturePointer getRenderBuffer(uint32 slot) const; + uint32 getRenderBufferSubresource(uint32 slot) const; + + bool setDepthStencilBuffer(const TexturePointer& texture, uint32 subresource = 0); + TexturePointer getDepthStencilBuffer() const; + uint32 getDepthStencilBufferSubresource() const; + + // Properties + uint32 getBuffersMask() const { return _buffersMask; } + bool isEmpty() const; + + bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const; + + uint16 getWidth() const; + uint16 getHeight() const; + uint16 getNumSamples() const; + + float getAspectRatio() const { return getWidth() / (float) getHeight() ; } + + // If not a swapchain canvas, resize can resize all the render buffers and depth stencil attached in one call + void resize( uint16 width, uint16 height, uint16 samples = 1 ); + + static const uint32 MAX_NUM_RENDER_BUFFERS = 8; + static uint32 getMaxNumRenderBuffers() { return MAX_NUM_RENDER_BUFFERS; } + + // Get viewport covering the ful Canvas + Viewport getViewport() const { return Viewport(getWidth(), getHeight(), 0, 0); } + + +protected: + + Viewport _viewport; + + uint16 _width; + uint16 _height; + uint16 _numSamples; + + uint32 _buffersMask; + + uint32 _frameCount; + + SwapchainPointer _swapchain; + + Textures _renderBuffers; + std::vector _renderBuffersSubresource; + + TexturePointer _depthStencilBuffer; + uint32 _depthStencilBufferSubresource; + + + void updateSize(const TexturePointer& texture); + + // Non exposed + Framebuffer(const Framebuffer& framebuffer) {} + Framebuffer(); + + // This shouldn't be used by anything else than the Backend class with the proper casting. + mutable GPUObject* _gpuObject = NULL; + void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; } + GPUObject* getGPUObject() const { return _gpuObject; } + friend class Backend; +}; + +} + +#endif \ No newline at end of file