You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
613 lines
22 KiB
613 lines
22 KiB
/*
|
|
* Copyright (C) 2011 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include "GLcommon/FramebufferData.h"
|
|
|
|
#include "base/StreamSerializing.h"
|
|
#include "GLcommon/GLEScontext.h"
|
|
#include "GLcommon/GLutils.h"
|
|
#include "GLcommon/TextureData.h"
|
|
|
|
#include <GLES/gl.h>
|
|
#include <GLES/glext.h>
|
|
|
|
RenderbufferData::RenderbufferData(android::base::Stream* stream) :
|
|
ObjectData(stream) {
|
|
attachedFB = stream->getBe32();
|
|
attachedPoint = stream->getBe32();
|
|
// TODO: load eglImageGlobalTexObject
|
|
width = stream->getBe32();
|
|
height = stream->getBe32();
|
|
internalformat = stream->getBe32();
|
|
hostInternalFormat = stream->getBe32();
|
|
everBound = stream->getBe32();
|
|
}
|
|
|
|
void RenderbufferData::onSave(android::base::Stream* stream, unsigned int globalName) const {
|
|
ObjectData::onSave(stream, globalName);
|
|
stream->putBe32(attachedFB);
|
|
stream->putBe32(attachedPoint);
|
|
// TODO: snapshot eglImageGlobalTexObject
|
|
if (eglImageGlobalTexObject) {
|
|
fprintf(stderr, "RenderbufferData::onSave: warning:"
|
|
" EglImage snapshot unimplemented. \n");
|
|
}
|
|
stream->putBe32(width);
|
|
stream->putBe32(height);
|
|
stream->putBe32(internalformat);
|
|
stream->putBe32(hostInternalFormat);
|
|
stream->putBe32(everBound);
|
|
}
|
|
|
|
void RenderbufferData::restore(ObjectLocalName localName,
|
|
const getGlobalName_t& getGlobalName) {
|
|
ObjectData::restore(localName, getGlobalName);
|
|
int globalName = getGlobalName(NamedObjectType::RENDERBUFFER,
|
|
localName);
|
|
GLDispatch& dispatcher = GLEScontext::dispatcher();
|
|
dispatcher.glBindRenderbuffer(GL_RENDERBUFFER, globalName);
|
|
if (hostInternalFormat != GL_NONE) {
|
|
dispatcher.glRenderbufferStorage(GL_RENDERBUFFER, hostInternalFormat,
|
|
width, height);
|
|
}
|
|
}
|
|
|
|
void RenderbufferData::makeTextureDirty() {
|
|
if (saveableTexture) {
|
|
saveableTexture->makeDirty();
|
|
}
|
|
}
|
|
|
|
static GLenum s_index2Attachment(int idx);
|
|
|
|
FramebufferData::FramebufferData(GLuint name, GLuint globalName) : ObjectData(FRAMEBUFFER_DATA)
|
|
, m_fbName(name), m_fbGlobalName(globalName) {
|
|
}
|
|
|
|
FramebufferData::FramebufferData(android::base::Stream* stream) :
|
|
ObjectData(stream) {
|
|
m_fbName = stream->getBe32();
|
|
int attachNum = stream->getBe32();
|
|
(void)attachNum;
|
|
assert(attachNum == MAX_ATTACH_POINTS);
|
|
for (auto& attachPoint : m_attachPoints) {
|
|
attachPoint.target = stream->getBe32();
|
|
attachPoint.name = stream->getBe32();
|
|
attachPoint.objType = (NamedObjectType)stream->getBe32();
|
|
// attachPoint.obj will be set up in postLoad
|
|
attachPoint.owned = stream->getByte();
|
|
}
|
|
m_dirty = stream->getByte();
|
|
m_hasBeenBound = stream->getByte();
|
|
m_hasDrawBuffers = stream->getByte();
|
|
android::base::loadBuffer(stream, &m_drawBuffers);
|
|
m_readBuffer = stream->getBe32();
|
|
}
|
|
|
|
FramebufferData::~FramebufferData() {
|
|
for (int i=0; i<MAX_ATTACH_POINTS; i++) {
|
|
detachObject(i);
|
|
}
|
|
}
|
|
|
|
void FramebufferData::onSave(android::base::Stream* stream, unsigned int globalName) const {
|
|
ObjectData::onSave(stream, globalName);
|
|
stream->putBe32(m_fbName);
|
|
stream->putBe32(MAX_ATTACH_POINTS);
|
|
for (auto& attachPoint : m_attachPoints) {
|
|
stream->putBe32(attachPoint.target);
|
|
stream->putBe32(attachPoint.name);
|
|
// do not save attachPoint.obj
|
|
if (attachPoint.obj) {
|
|
stream->putBe32((uint32_t)ObjectDataType2NamedObjectType(
|
|
attachPoint.obj->getDataType()));
|
|
} else {
|
|
stream->putBe32((uint32_t)NamedObjectType::NULLTYPE);
|
|
}
|
|
stream->putByte(attachPoint.owned);
|
|
}
|
|
stream->putByte(m_dirty);
|
|
stream->putByte(m_hasBeenBound);
|
|
stream->putByte(m_hasDrawBuffers);
|
|
android::base::saveBuffer(stream, m_drawBuffers);
|
|
stream->putBe32(m_readBuffer);
|
|
}
|
|
|
|
void FramebufferData::postLoad(const getObjDataPtr_t& getObjDataPtr) {
|
|
for (auto& attachPoint : m_attachPoints) {
|
|
if (NamedObjectType::NULLTYPE != attachPoint.objType) {
|
|
attachPoint.obj = getObjDataPtr(attachPoint.objType,
|
|
attachPoint.name);
|
|
if (!attachPoint.obj) {
|
|
fprintf(stderr, "FramebufferData::postLoad: warning: "
|
|
"bound render buffer restore failed.\n");
|
|
attachPoint.obj.reset(new RenderbufferData);
|
|
}
|
|
} else {
|
|
attachPoint.obj = {};
|
|
}
|
|
}
|
|
}
|
|
|
|
void FramebufferData::restore(ObjectLocalName localName,
|
|
const getGlobalName_t& getGlobalName) {
|
|
ObjectData::restore(localName, getGlobalName);
|
|
if (!hasBeenBoundAtLeastOnce()) return;
|
|
int globalName = getGlobalName(NamedObjectType::FRAMEBUFFER,
|
|
localName);
|
|
GLDispatch& dispatcher = GLEScontext::dispatcher();
|
|
dispatcher.glBindFramebuffer(GL_FRAMEBUFFER, globalName);
|
|
for (int i = 0; i < MAX_ATTACH_POINTS; i++) {
|
|
auto& attachPoint = m_attachPoints[i];
|
|
if (!attachPoint.name) continue; // bound to nothing
|
|
// attachPoint.owned is true only when color buffer 0 is
|
|
// not bound. In such situation, it will generate its own object when
|
|
// calling validate()
|
|
if (attachPoint.owned) {
|
|
attachPoint.name = 0;
|
|
continue;
|
|
}
|
|
if (attachPoint.obj) { // binding a render buffer
|
|
assert(attachPoint.obj->getDataType()
|
|
== RENDERBUFFER_DATA);
|
|
attachPoint.globalName =
|
|
getGlobalName(NamedObjectType::RENDERBUFFER,
|
|
attachPoint.name);
|
|
RenderbufferData *rbData = (RenderbufferData*)attachPoint.obj.get();
|
|
if (rbData->eglImageGlobalTexObject) {
|
|
fprintf(stderr, "FramebufferData::restore: warning: "
|
|
"binding egl image unsupported\n");
|
|
} else {
|
|
assert(attachPoint.target == GL_RENDERBUFFER);
|
|
dispatcher.glFramebufferRenderbuffer(
|
|
GL_FRAMEBUFFER,
|
|
s_index2Attachment(i),
|
|
attachPoint.target,
|
|
attachPoint.globalName);
|
|
}
|
|
} else { // binding a texture
|
|
int texGlobalName = getGlobalName(NamedObjectType::TEXTURE,
|
|
attachPoint.name);
|
|
attachPoint.globalName = texGlobalName;
|
|
if (!texGlobalName) {
|
|
fprintf(stderr, "FramebufferData::restore: warning: "
|
|
"a texture is deleted without unbinding FBO\n");
|
|
}
|
|
dispatcher.glFramebufferTexture2D(GL_FRAMEBUFFER,
|
|
s_index2Attachment(i),
|
|
attachPoint.target,
|
|
texGlobalName,
|
|
0);
|
|
}
|
|
}
|
|
m_dirty = true;
|
|
if (m_hasDrawBuffers) {
|
|
dispatcher.glDrawBuffers(m_drawBuffers.size(), m_drawBuffers.data());
|
|
}
|
|
if (dispatcher.glReadBuffer) {
|
|
dispatcher.glReadBuffer(m_readBuffer);
|
|
}
|
|
}
|
|
|
|
void FramebufferData::makeTextureDirty(const getObjDataPtr_t& getObjDataPtr) {
|
|
if (!hasBeenBoundAtLeastOnce()) return;
|
|
for (int i = 0; i < MAX_ATTACH_POINTS; i++) {
|
|
auto& attachPoint = m_attachPoints[i];
|
|
if (!attachPoint.name || attachPoint.owned || attachPoint.obj) {
|
|
// If not bound to a texture, do nothing
|
|
continue;
|
|
}
|
|
TextureData* texData = (TextureData*)getObjDataPtr(
|
|
NamedObjectType::TEXTURE, attachPoint.name).get();
|
|
if (texData) {
|
|
texData->makeDirty();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FramebufferData::setAttachment(
|
|
class GLEScontext* ctx,
|
|
GLenum attachment,
|
|
GLenum target,
|
|
GLuint name,
|
|
ObjectDataPtr obj,
|
|
bool takeOwnership) {
|
|
|
|
int idx = attachmentPointIndex(attachment);
|
|
|
|
if (!name) {
|
|
detachObject(idx);
|
|
return;
|
|
}
|
|
if (m_attachPoints[idx].target != target ||
|
|
m_attachPoints[idx].name != name ||
|
|
m_attachPoints[idx].obj.get() != obj.get() ||
|
|
m_attachPoints[idx].owned != takeOwnership) {
|
|
detachObject(idx);
|
|
|
|
m_attachPoints[idx].target = target;
|
|
m_attachPoints[idx].name = name;
|
|
|
|
NamedObjectType namedObjectType =
|
|
target == GL_RENDERBUFFER ?
|
|
NamedObjectType::RENDERBUFFER :
|
|
NamedObjectType::TEXTURE;
|
|
|
|
m_attachPoints[idx].globalName =
|
|
name ? ctx->shareGroup()->getGlobalName(namedObjectType, name) : 0;
|
|
|
|
m_attachPoints[idx].obj = obj;
|
|
m_attachPoints[idx].owned = takeOwnership;
|
|
|
|
if (target == GL_RENDERBUFFER_OES && obj.get() != NULL) {
|
|
RenderbufferData *rbData = (RenderbufferData *)obj.get();
|
|
rbData->attachedFB = m_fbName;
|
|
rbData->attachedPoint = attachment;
|
|
}
|
|
|
|
m_dirty = true;
|
|
|
|
refreshSeparateDepthStencilAttachmentState();
|
|
}
|
|
}
|
|
|
|
GLuint FramebufferData::getAttachment(GLenum attachment,
|
|
GLenum *outTarget,
|
|
ObjectDataPtr *outObj) {
|
|
int idx = attachmentPointIndex(attachment);
|
|
if (outTarget) *outTarget = m_attachPoints[idx].target;
|
|
if (outObj) *outObj = m_attachPoints[idx].obj;
|
|
return m_attachPoints[idx].name;
|
|
}
|
|
|
|
GLint FramebufferData::getAttachmentSamples(GLEScontext* ctx, GLenum attachment) {
|
|
int idx = attachmentPointIndex(attachment);
|
|
|
|
// Don't expose own attachments.
|
|
if (m_attachPoints[idx].owned) return 0;
|
|
|
|
GLenum target = m_attachPoints[idx].target;
|
|
GLuint name = m_attachPoints[idx].name;
|
|
|
|
if (target == GL_RENDERBUFFER) {
|
|
RenderbufferData* rbData = (RenderbufferData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, name);
|
|
return rbData ? rbData->samples : 0;
|
|
} else {
|
|
TextureData* texData = (TextureData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, name);
|
|
return texData ? texData->samples : 0;
|
|
}
|
|
}
|
|
|
|
void FramebufferData::getAttachmentDimensions(GLEScontext* ctx, GLenum attachment, GLint* width, GLint* height) {
|
|
int idx = attachmentPointIndex(attachment);
|
|
|
|
// Don't expose own attachments.
|
|
if (m_attachPoints[idx].owned) return;
|
|
|
|
GLenum target = m_attachPoints[idx].target;
|
|
GLuint name = m_attachPoints[idx].name;
|
|
|
|
if (target == GL_RENDERBUFFER) {
|
|
RenderbufferData* rbData = (RenderbufferData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, name);
|
|
if (rbData) {
|
|
*width = rbData->width;
|
|
*height = rbData->height;
|
|
}
|
|
} else {
|
|
TextureData* texData = (TextureData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, name);
|
|
if (texData) {
|
|
*width = texData->width;
|
|
*height = texData->height;
|
|
}
|
|
}
|
|
}
|
|
|
|
GLint FramebufferData::getAttachmentInternalFormat(GLEScontext* ctx, GLenum attachment) {
|
|
int idx = attachmentPointIndex(attachment);
|
|
|
|
// Don't expose own attachments.
|
|
if (m_attachPoints[idx].owned) return 0;
|
|
|
|
GLenum target = m_attachPoints[idx].target;
|
|
GLuint name = m_attachPoints[idx].name;
|
|
|
|
if (target == GL_RENDERBUFFER) {
|
|
RenderbufferData* rbData = (RenderbufferData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, name);
|
|
return rbData ? rbData->internalformat : 0;
|
|
} else {
|
|
TextureData* texData = (TextureData*)
|
|
ctx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, name);
|
|
return texData? texData->internalFormat : 0;
|
|
}
|
|
}
|
|
|
|
void FramebufferData::separateDepthStencilWorkaround(GLEScontext* ctx) {
|
|
// Swiftshader does not need the workaround as it allows separate depth/stencil.
|
|
if (isGles2Gles()) return;
|
|
|
|
// bug: 78083376
|
|
//
|
|
// Some apps rely on using separate depth/stencil attachments with separate
|
|
// backing images. This affects macOS OpenGL because it does not allow
|
|
// separate depth/stencil attachments with separate backing images.
|
|
//
|
|
// Emulate them here with a single combined backing image.
|
|
#ifdef __APPLE__
|
|
if (!m_hasSeparateDepthStencil || m_separateDSEmulationRbo) return;
|
|
|
|
GLuint prevRboBinding;
|
|
GLuint prevFboBinding;
|
|
auto& gl = ctx->dispatcher();
|
|
// Use the depth stencil's dimensions.
|
|
GLint widthDepth;
|
|
GLint heightDepth;
|
|
getAttachmentDimensions(ctx, GL_DEPTH_ATTACHMENT,
|
|
&widthDepth, &heightDepth);
|
|
|
|
gl.glGetIntegerv(GL_RENDERBUFFER_BINDING, (GLint*)&prevRboBinding);
|
|
gl.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&prevFboBinding);
|
|
|
|
gl.glGenRenderbuffers(1, &m_separateDSEmulationRbo);
|
|
gl.glBindRenderbuffer(GL_RENDERBUFFER, m_separateDSEmulationRbo);
|
|
gl.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
|
|
widthDepth, heightDepth);
|
|
|
|
gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbGlobalName);
|
|
gl.glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
|
|
GL_RENDERBUFFER, m_separateDSEmulationRbo);
|
|
gl.glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
|
GL_RENDERBUFFER, m_separateDSEmulationRbo);
|
|
|
|
gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFboBinding);
|
|
gl.glBindRenderbuffer(GL_RENDERBUFFER, prevRboBinding);
|
|
#endif
|
|
}
|
|
|
|
int FramebufferData::attachmentPointIndex(GLenum attachment)
|
|
{
|
|
switch(attachment) {
|
|
case GL_COLOR_ATTACHMENT0_OES:
|
|
return 0;
|
|
case GL_DEPTH_ATTACHMENT_OES:
|
|
return 1;
|
|
case GL_STENCIL_ATTACHMENT_OES:
|
|
return 2;
|
|
case GL_DEPTH_STENCIL_ATTACHMENT:
|
|
return 3;
|
|
default:
|
|
{
|
|
// for colorbuffer 1 ~ 15, they are continuous
|
|
int idx = attachment - GL_COLOR_ATTACHMENT1 + 4;
|
|
// in case for some new attachment extensions
|
|
if (idx < 4 || idx > MAX_ATTACH_POINTS) {
|
|
idx = MAX_ATTACH_POINTS;
|
|
}
|
|
return idx;
|
|
}
|
|
}
|
|
}
|
|
|
|
static GLenum s_index2Attachment(int idx) {
|
|
switch (idx) {
|
|
case 0:
|
|
return GL_COLOR_ATTACHMENT0_OES;
|
|
case 1:
|
|
return GL_DEPTH_ATTACHMENT_OES;
|
|
case 2:
|
|
return GL_STENCIL_ATTACHMENT_OES;
|
|
case 3:
|
|
return GL_DEPTH_STENCIL_ATTACHMENT;
|
|
default:
|
|
return idx - 4 + GL_COLOR_ATTACHMENT1;
|
|
}
|
|
}
|
|
|
|
void FramebufferData::detachObject(int idx) {
|
|
if (m_attachPoints[idx].target == GL_RENDERBUFFER_OES && m_attachPoints[idx].obj.get() != NULL) {
|
|
RenderbufferData *rbData = (RenderbufferData *)m_attachPoints[idx].obj.get();
|
|
rbData->attachedFB = 0;
|
|
rbData->attachedPoint = 0;
|
|
}
|
|
|
|
if(m_attachPoints[idx].owned)
|
|
{
|
|
switch(m_attachPoints[idx].target)
|
|
{
|
|
case GL_RENDERBUFFER_OES:
|
|
GLEScontext::dispatcher().glDeleteRenderbuffers(1, &(m_attachPoints[idx].name));
|
|
break;
|
|
case GL_TEXTURE_2D:
|
|
GLEScontext::dispatcher().glDeleteTextures(1, &(m_attachPoints[idx].name));
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_attachPoints[idx] = {};
|
|
|
|
refreshSeparateDepthStencilAttachmentState();
|
|
}
|
|
|
|
// bug: 78083376
|
|
//
|
|
// Check attachment state and delete / recreate original depth/stencil
|
|
// attachments if necessary.
|
|
//
|
|
void FramebufferData::refreshSeparateDepthStencilAttachmentState() {
|
|
m_hasSeparateDepthStencil = false;
|
|
|
|
ObjectDataPtr depthObject =
|
|
m_attachPoints[attachmentPointIndex(GL_DEPTH_ATTACHMENT)].obj;
|
|
ObjectDataPtr stencilObject =
|
|
m_attachPoints[attachmentPointIndex(GL_STENCIL_ATTACHMENT)].obj;
|
|
|
|
m_hasSeparateDepthStencil = depthObject && stencilObject && (depthObject != stencilObject);
|
|
|
|
if (m_hasSeparateDepthStencil) return;
|
|
|
|
// Delete the emulated RBO and restore the original
|
|
// if we don't have separate depth/stencil anymore.
|
|
auto& gl = GLEScontext::dispatcher();
|
|
|
|
if (!m_separateDSEmulationRbo) return;
|
|
|
|
gl.glDeleteRenderbuffers(1, &m_separateDSEmulationRbo);
|
|
m_separateDSEmulationRbo = 0;
|
|
|
|
// Now that we don't have separate depth/stencil attachments,
|
|
// we might need to restore one of the original attachments,
|
|
// because we were using a nonzero m_separateDSEmulationRbo.
|
|
GLenum attachmentToRestore =
|
|
m_attachPoints[attachmentPointIndex(GL_DEPTH_ATTACHMENT)].name ?
|
|
GL_DEPTH_ATTACHMENT : (
|
|
m_attachPoints[attachmentPointIndex(GL_STENCIL_ATTACHMENT)].name ?
|
|
GL_STENCIL_ATTACHMENT : 0);
|
|
|
|
if (!attachmentToRestore) return;
|
|
|
|
GLuint objectToRestore =
|
|
m_attachPoints[attachmentPointIndex(attachmentToRestore)].globalName;
|
|
|
|
GLenum objectTypeToRestore =
|
|
m_attachPoints[attachmentPointIndex(attachmentToRestore)].target;
|
|
|
|
GLuint prevFboBinding;
|
|
gl.glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&prevFboBinding);
|
|
gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbGlobalName);
|
|
|
|
switch (objectTypeToRestore) {
|
|
case GL_RENDERBUFFER:
|
|
gl.glFramebufferRenderbuffer(
|
|
GL_DRAW_FRAMEBUFFER,
|
|
attachmentToRestore,
|
|
GL_RENDERBUFFER,
|
|
objectToRestore);
|
|
break;
|
|
case GL_TEXTURE_2D:
|
|
gl.glFramebufferTexture2D(
|
|
GL_DRAW_FRAMEBUFFER,
|
|
attachmentToRestore,
|
|
GL_TEXTURE_2D,
|
|
objectToRestore, 0);
|
|
break;
|
|
}
|
|
|
|
gl.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFboBinding);
|
|
}
|
|
|
|
void FramebufferData::validate(GLEScontext* ctx)
|
|
{
|
|
// Do not validate if on another GLES2 backend
|
|
if (isGles2Gles()) return;
|
|
if(!getAttachment(GL_COLOR_ATTACHMENT0_OES, NULL, NULL))
|
|
{
|
|
// GLES does not require the framebuffer to have a color attachment.
|
|
// OpenGL does. Therefore, if no color is attached, create a dummy
|
|
// color texture and attach it.
|
|
// This dummy color texture will is owned by the FramebufferObject,
|
|
// and will be released by it when its object is detached.
|
|
|
|
GLint type = GL_NONE;
|
|
GLint name = 0;
|
|
|
|
ctx->dispatcher().glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
|
|
if(type != GL_NONE)
|
|
{
|
|
ctx->dispatcher().glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
|
|
}
|
|
else
|
|
{
|
|
ctx->dispatcher().glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
|
|
if(type != GL_NONE)
|
|
{
|
|
ctx->dispatcher().glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
|
|
}
|
|
else
|
|
{
|
|
// No color, depth or stencil attachments - do nothing
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Find the existing attachment(s) dimensions
|
|
GLint width = 0;
|
|
GLint height = 0;
|
|
|
|
if(type == GL_RENDERBUFFER)
|
|
{
|
|
GLint prev;
|
|
ctx->dispatcher().glGetIntegerv(GL_RENDERBUFFER_BINDING, &prev);
|
|
ctx->dispatcher().glBindRenderbuffer(GL_RENDERBUFFER, name);
|
|
ctx->dispatcher().glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
|
|
ctx->dispatcher().glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
|
|
ctx->dispatcher().glBindRenderbuffer(GL_RENDERBUFFER, prev);
|
|
}
|
|
else if(type == GL_TEXTURE)
|
|
{
|
|
GLint prev;
|
|
ctx->dispatcher().glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev);
|
|
ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, name);
|
|
ctx->dispatcher().glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
|
ctx->dispatcher().glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
|
ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, prev);
|
|
}
|
|
|
|
// Create the color attachment and attch it
|
|
unsigned int tex = 0;
|
|
ctx->dispatcher().glGenTextures(1, &tex);
|
|
GLint prev;
|
|
ctx->dispatcher().glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev);
|
|
ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, tex);
|
|
|
|
ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
|
|
ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
|
|
ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
|
|
ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
|
|
ctx->dispatcher().glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
ctx->dispatcher().glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex, 0);
|
|
setAttachment(ctx, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex, ObjectDataPtr(), true);
|
|
|
|
ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, prev);
|
|
}
|
|
|
|
if(m_dirty)
|
|
{
|
|
// This is a workaround for a bug found in several OpenGL
|
|
// drivers (e.g. ATI's) - after the framebuffer attachments
|
|
// have changed, and before the next draw, unbind and rebind
|
|
// the framebuffer to sort things out.
|
|
ctx->dispatcher().glBindFramebuffer(GL_FRAMEBUFFER,0);
|
|
ctx->dispatcher().glBindFramebuffer(
|
|
GL_FRAMEBUFFER, m_fbGlobalName);
|
|
|
|
m_dirty = false;
|
|
}
|
|
}
|
|
|
|
void FramebufferData::setDrawBuffers(GLsizei n, const GLenum * bufs) {
|
|
m_drawBuffers.resize(n);
|
|
memcpy(m_drawBuffers.data(), bufs, n * sizeof(GLenum));
|
|
m_hasDrawBuffers = true;
|
|
}
|
|
|
|
void FramebufferData::setReadBuffers(GLenum src) {
|
|
m_readBuffer = src;
|
|
}
|