Creating the Framebuffer class and the companion Swapbuffer

This commit is contained in:
Sam Gateau 2015-04-12 17:36:45 -07:00
parent 4ad5a6c138
commit 69484ad00b
3 changed files with 463 additions and 0 deletions

View file

@ -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 {

View file

@ -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 <math.h>
#include <QDebug>
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<<slot);
_buffersMask = (_buffersMask & ~(mask));
if (texture) {
_buffersMask |= mask;
}
return slot;
}
void Framebuffer::removeRenderBuffers() {
if (isSwapchain()) {
return;
}
_buffersMask = _buffersMask & BUFFER_DEPTHSTENCIL;
for (auto renderBuffer : _renderBuffers) {
renderBuffer.reset();
}
updateSize(TexturePointer(nullptr));
}
uint32 Framebuffer::getNumRenderBuffers() const {
uint32 nb = 0;
for (auto i : _renderBuffers) {
nb += (!i);
}
return nb;
}
TexturePointer Framebuffer::getRenderBuffer(uint32 slot) const {
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
return _renderBuffers[slot];
} else {
return TexturePointer();
}
}
uint32 Framebuffer::getRenderBufferSubresource(uint32 slot) const {
if (!isSwapchain() && (slot < getMaxNumRenderBuffers())) {
return _renderBuffersSubresource[slot];
} else {
return 0;
}
}
bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, uint32 subresource) {
if (isSwapchain()) {
return false;
}
// Check for the compatibility of size
if (texture) {
if (!validateTargetCompatibility(*texture)) {
return false;
}
}
// Checks ok, assign
_depthStencilBuffer.reset();
_depthStencilBufferSubresource = 0;
updateSize(texture);
// assign the new one
_depthStencilBuffer = texture;
_depthStencilBufferSubresource = subresource;
_buffersMask = ( _buffersMask & ~BUFFER_DEPTHSTENCIL);
if (texture) {
_buffersMask |= BUFFER_DEPTHSTENCIL;
}
return true;
}
TexturePointer Framebuffer::getDepthStencilBuffer() const {
if (isSwapchain()) {
return TexturePointer();
} else {
return _depthStencilBuffer;
}
}
uint32 Framebuffer::getDepthStencilBufferSubresource() const {
if (isSwapchain()) {
return 0;
} else {
return _depthStencilBufferSubresource;
}
}

View file

@ -0,0 +1,195 @@
//
// Framebuffer.h
// 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
//
#ifndef hifi_gpu_Framebuffer_h
#define hifi_gpu_Framebuffer_h
#include "Texture.h"
#include <memory>
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<Swapchain> 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<uint32> _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