blob: 162af344abc02dc7f8eec07387a08cc8813827c6 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include "gpu/command_buffer/service/error_state_mock.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "gpu/command_buffer/service/gpu_service_test.h"
#include "gpu/command_buffer/service/renderbuffer_manager.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_mock.h"
using ::testing::_;
using ::testing::Return;
namespace gpu {
namespace gles2 {
namespace {
const GLint kMaxTextureSize = 64;
const GLint kMaxCubemapSize = 64;
const GLint kMaxRectangleTextureSize = 64;
const GLint kMax3DTextureSize = 256;
const GLint kMaxArrayTextureLayers = 256;
const GLint kMaxRenderbufferSize = 64;
const GLint kMaxSamples = 4;
const uint32_t kMaxDrawBuffers = 16;
const uint32_t kMaxColorAttachments = 16;
const bool kUseDefaultTextures = false;
} // namespace
class FramebufferManagerTest : public GpuServiceTest {
public:
FramebufferManagerTest()
: manager_(1, 1, nullptr),
feature_info_(new FeatureInfo()) {
texture_manager_.reset(new TextureManager(
nullptr, feature_info_.get(), kMaxTextureSize, kMaxCubemapSize,
kMaxRectangleTextureSize, kMax3DTextureSize, kMaxArrayTextureLayers,
kUseDefaultTextures, nullptr));
renderbuffer_manager_.reset(new RenderbufferManager(nullptr,
kMaxRenderbufferSize,
kMaxSamples,
feature_info_.get()));
}
~FramebufferManagerTest() override {
manager_.Destroy(false);
texture_manager_->Destroy(false);
renderbuffer_manager_->Destroy(false);
}
protected:
FramebufferManager manager_;
scoped_refptr<FeatureInfo> feature_info_;
std::unique_ptr<TextureManager> texture_manager_;
std::unique_ptr<RenderbufferManager> renderbuffer_manager_;
};
TEST_F(FramebufferManagerTest, Basic) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
const GLuint kClient2Id = 2;
// Check we can create framebuffer.
manager_.CreateFramebuffer(kClient1Id, kService1Id);
// Check framebuffer got created.
Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id);
ASSERT_TRUE(framebuffer1 != nullptr);
EXPECT_FALSE(framebuffer1->IsDeleted());
EXPECT_EQ(kService1Id, framebuffer1->service_id());
GLuint client_id = 0;
EXPECT_TRUE(manager_.GetClientId(framebuffer1->service_id(), &client_id));
EXPECT_EQ(kClient1Id, client_id);
// Check we get nothing for a non-existent framebuffer.
EXPECT_TRUE(manager_.GetFramebuffer(kClient2Id) == nullptr);
// Check trying to a remove non-existent framebuffers does not crash.
manager_.RemoveFramebuffer(kClient2Id);
// Check framebuffer gets deleted when last reference is released.
EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id)))
.Times(1)
.RetiresOnSaturation();
// Check we can't get the framebuffer after we remove it.
manager_.RemoveFramebuffer(kClient1Id);
EXPECT_TRUE(manager_.GetFramebuffer(kClient1Id) == nullptr);
}
TEST_F(FramebufferManagerTest, Destroy) {
const GLuint kClient1Id = 1;
const GLuint kService1Id = 11;
// Check we can create framebuffer.
manager_.CreateFramebuffer(kClient1Id, kService1Id);
// Check framebuffer got created.
Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id);
ASSERT_TRUE(framebuffer1 != nullptr);
EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id)))
.Times(1)
.RetiresOnSaturation();
manager_.Destroy(true);
// Check the resources were released.
framebuffer1 = manager_.GetFramebuffer(kClient1Id);
ASSERT_TRUE(framebuffer1 == nullptr);
}
class FramebufferInfoTestBase : public GpuServiceTest {
public:
static const GLuint kClient1Id = 1;
static const GLuint kService1Id = 11;
explicit FramebufferInfoTestBase(ContextType context_type)
: context_type_(context_type),
manager_(kMaxDrawBuffers,
kMaxColorAttachments,
new FramebufferCompletenessCache),
feature_info_(new FeatureInfo()) {
texture_manager_.reset(new TextureManager(
nullptr, feature_info_.get(), kMaxTextureSize, kMaxCubemapSize,
kMaxRectangleTextureSize, kMax3DTextureSize, kMaxArrayTextureLayers,
kUseDefaultTextures, nullptr));
renderbuffer_manager_.reset(new RenderbufferManager(nullptr,
kMaxRenderbufferSize,
kMaxSamples,
feature_info_.get()));
}
~FramebufferInfoTestBase() override {
manager_.Destroy(false);
texture_manager_->Destroy(false);
renderbuffer_manager_->Destroy(false);
}
protected:
void SetUp() override {
bool is_es3 = false;
if (context_type_ == CONTEXT_TYPE_WEBGL2 ||
context_type_ == CONTEXT_TYPE_OPENGLES3)
is_es3 = true;
InitializeContext(is_es3 ? "3.0" : "2.0", "GL_EXT_framebuffer_object");
}
void InitializeContext(const char* gl_version, const char* extensions) {
GpuServiceTest::SetUpWithGLVersion(gl_version, extensions);
TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(gl_.get(),
extensions, "", gl_version, context_type_);
feature_info_->InitializeForTesting(context_type_);
decoder_.reset(new MockGLES2Decoder());
manager_.CreateFramebuffer(kClient1Id, kService1Id);
error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
framebuffer_ = manager_.GetFramebuffer(kClient1Id);
ASSERT_TRUE(framebuffer_ != nullptr);
}
ContextType context_type_;
FramebufferManager manager_;
Framebuffer* framebuffer_;
scoped_refptr<FeatureInfo> feature_info_;
std::unique_ptr<TextureManager> texture_manager_;
std::unique_ptr<RenderbufferManager> renderbuffer_manager_;
std::unique_ptr<MockErrorState> error_state_;
std::unique_ptr<MockGLES2Decoder> decoder_;
};
class FramebufferInfoTest : public FramebufferInfoTestBase {
public:
FramebufferInfoTest() : FramebufferInfoTestBase(CONTEXT_TYPE_OPENGLES2) {}
};
// GCC requires these declarations, but MSVC requires they not be present
#ifndef COMPILER_MSVC
const GLuint FramebufferInfoTestBase::kClient1Id;
const GLuint FramebufferInfoTestBase::kService1Id;
#endif
TEST_F(FramebufferInfoTest, Basic) {
EXPECT_EQ(kService1Id, framebuffer_->service_id());
EXPECT_FALSE(framebuffer_->IsDeleted());
EXPECT_TRUE(nullptr == framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(nullptr == framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_TRUE(nullptr == framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasDepthAttachment());
EXPECT_FALSE(framebuffer_->HasStencilAttachment());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_FALSE(manager_.IsComplete(framebuffer_));
}
TEST_F(FramebufferInfoTest, AttachRenderbuffer) {
const GLuint kRenderbufferClient1Id = 33;
const GLuint kRenderbufferService1Id = 333;
const GLuint kRenderbufferClient2Id = 34;
const GLuint kRenderbufferService2Id = 334;
const GLuint kRenderbufferClient3Id = 35;
const GLuint kRenderbufferService3Id = 335;
const GLuint kRenderbufferClient4Id = 36;
const GLuint kRenderbufferService4Id = 336;
const GLuint kRenderbufferClient5Id = 37;
const GLuint kRenderbufferService5Id = 337;
const GLsizei kWidth1 = 16;
const GLsizei kHeight1 = 32;
const GLenum kFormat1 = GL_RGBA4;
const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16;
const GLsizei kSamples1 = 0;
const GLsizei kWidth2 = 16;
const GLsizei kHeight2 = 32;
const GLenum kFormat2 = GL_DEPTH_COMPONENT16;
const GLsizei kSamples2 = 0;
const GLsizei kWidth3 = 16;
const GLsizei kHeight3 = 32;
const GLenum kFormat3 = GL_STENCIL_INDEX8;
const GLsizei kSamples3 = 0;
const GLsizei kWidth4 = 16;
const GLsizei kHeight4 = 32;
const GLenum kFormat4 = GL_DEPTH24_STENCIL8;
const GLsizei kSamples4 = 0;
const GLsizei kWidth5 = 16;
const GLsizei kHeight5 = 32;
const GLenum kFormat5 = GL_DEPTH24_STENCIL8;
const GLsizei kSamples5 = 0;
const GLsizei kDifferentSamples5 = 1;
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient1Id, kRenderbufferService1Id);
Renderbuffer* renderbuffer1 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id);
ASSERT_TRUE(renderbuffer1 != nullptr);
// Check adding one attachment.
framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(GL_RGBA4),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_FALSE(framebuffer_->HasDepthAttachment());
EXPECT_FALSE(framebuffer_->HasStencilAttachment());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
// Try a format that's not good for COLOR_ATTACHMENT0.
renderbuffer_manager_->SetInfo(
renderbuffer1, kSamples1, kBadFormat1, kWidth1, kHeight1);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Try a good format.
renderbuffer_manager_->SetInfo(
renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1);
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_FALSE(framebuffer_->HasDepthAttachment());
EXPECT_FALSE(framebuffer_->HasStencilAttachment());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
// Check adding another.
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient2Id, kRenderbufferService2Id);
Renderbuffer* renderbuffer2 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id);
ASSERT_TRUE(renderbuffer2 != nullptr);
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer2);
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_TRUE(framebuffer_->HasDepthAttachment());
EXPECT_FALSE(framebuffer_->HasStencilAttachment());
// The attachment has a size of 0,0 so depending on the order of the map
// of attachments it could either get INCOMPLETE_ATTACHMENT because it's 0,0
// or INCOMPLETE_DIMENSIONS because it's not the same size as the other
// attachment.
GLenum status = framebuffer_->IsPossiblyComplete(feature_info_.get());
EXPECT_TRUE(
status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ||
status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT);
EXPECT_FALSE(framebuffer_->IsCleared());
renderbuffer_manager_->SetInfo(
renderbuffer2, kSamples2, kFormat2, kWidth2, kHeight2);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
// Check marking them as cleared.
manager_.MarkAttachmentsAsCleared(
framebuffer_, renderbuffer_manager_.get(), texture_manager_.get());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
// Add another one to stencil attachment point.
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient3Id, kRenderbufferService3Id);
Renderbuffer* renderbuffer3 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient3Id);
ASSERT_TRUE(renderbuffer3 != nullptr);
renderbuffer_manager_->SetInfo(
renderbuffer3, kSamples3, kFormat3, kWidth3, kHeight3);
renderbuffer_manager_->SetCleared(renderbuffer3, true);
framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer3);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_TRUE(framebuffer_->HasDepthAttachment());
EXPECT_TRUE(framebuffer_->HasStencilAttachment());
// Binding different images to depth and stencil attachment points should
// return FRAMEBUFFER_UNSUPPORTED.
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_UNSUPPORTED),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Bind a renderbufer in format DEPTH_STENCIL to depth and stencil
// attachment points.
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient4Id, kRenderbufferService4Id);
Renderbuffer* renderbuffer4 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient4Id);
ASSERT_TRUE(renderbuffer4 != nullptr);
renderbuffer_manager_->SetInfo(
renderbuffer4, kSamples4, kFormat4, kWidth4, kHeight4);
renderbuffer_manager_->SetCleared(renderbuffer4, true);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer4);
framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer4);
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_TRUE(framebuffer_->HasDepthAttachment());
EXPECT_TRUE(framebuffer_->HasStencilAttachment());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
// Check marking the renderbuffer as uncleared.
renderbuffer_manager_->SetInfo(
renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1);
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_TRUE(framebuffer_->HasDepthAttachment());
EXPECT_TRUE(framebuffer_->HasStencilAttachment());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth1, attachment->width());
EXPECT_EQ(kHeight1, attachment->height());
EXPECT_EQ(kSamples1, attachment->samples());
EXPECT_EQ(kFormat1, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
// Clear it.
manager_.MarkAttachmentsAsCleared(
framebuffer_, renderbuffer_manager_.get(), texture_manager_.get());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->IsCleared());
// Check replacing one attachment when both depth and stencil attachments
// are present.
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient5Id, kRenderbufferService5Id);
Renderbuffer* renderbuffer5 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient5Id);
ASSERT_TRUE(renderbuffer5 != nullptr);
renderbuffer_manager_->SetInfo(
renderbuffer5, kSamples5, kFormat5, kWidth5, kHeight5);
framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer5);
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_FALSE(framebuffer_->IsCleared());
attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth5, attachment->width());
EXPECT_EQ(kHeight5, attachment->height());
EXPECT_EQ(kSamples5, attachment->samples());
EXPECT_EQ(kFormat5, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
// Binding different images to depth and stencil attachment points should
// return FRAMEBUFFER_UNSUPPORTED.
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_UNSUPPORTED),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Check replacing both depth and stencil attachments.
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer5);
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_FALSE(framebuffer_->IsCleared());
attachment = framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT);
EXPECT_EQ(kWidth5, attachment->width());
EXPECT_EQ(kHeight5, attachment->height());
EXPECT_EQ(kSamples5, attachment->samples());
EXPECT_EQ(kFormat5, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Change samples.
ASSERT_FALSE(
feature_info_->feature_flags().chromium_framebuffer_mixed_samples);
renderbuffer_manager_->SetInfo(
renderbuffer5, kDifferentSamples5, kFormat5, kWidth5, kHeight5);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
renderbuffer_manager_->SetInfo(
renderbuffer5, kSamples5, kFormat5, kWidth5, kHeight5);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Check changing an attachment.
renderbuffer_manager_->SetInfo(
renderbuffer5, kSamples5, kFormat5, kWidth5 + 1, kHeight5);
attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth5 + 1, attachment->width());
EXPECT_EQ(kHeight5, attachment->height());
EXPECT_EQ(kSamples5, attachment->samples());
EXPECT_EQ(kFormat5, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Check removing it.
// Restore the width of renderbuffer5 to avoid INCOMPLETE_DIMENSIONS_EXT.
renderbuffer_manager_->SetInfo(
renderbuffer5, kSamples5, kFormat5, kWidth5, kHeight5);
framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, nullptr);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_TRUE(framebuffer_->HasDepthAttachment());
EXPECT_FALSE(framebuffer_->HasStencilAttachment());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Remove depth, Set color to 0 size.
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, nullptr);
renderbuffer_manager_->SetInfo(renderbuffer1, kSamples1, kFormat1, 0, 0);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Remove color.
framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, nullptr);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
}
TEST_F(FramebufferInfoTest, AttachTexture2D) {
const GLuint kTextureClient1Id = 33;
const GLuint kTextureService1Id = 333;
const GLuint kTextureClient2Id = 34;
const GLuint kTextureService2Id = 334;
const GLint kDepth = 1;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLsizei kWidth1 = 16;
const GLsizei kHeight1 = 32;
const GLint kLevel1 = 0;
const GLenum kFormat1 = GL_RGBA;
const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16;
const GLenum kTarget1 = GL_TEXTURE_2D;
const GLsizei kSamples1 = 0;
const GLsizei kWidth2 = 16;
const GLsizei kHeight2 = 32;
const GLint kLevel2 = 0;
const GLenum kFormat2 = GL_RGB;
const GLenum kTarget2 = GL_TEXTURE_2D;
const GLsizei kSamples2 = 0;
const GLsizei kWidth3 = 75;
const GLsizei kHeight3 = 123;
const GLint kLevel3 = 0;
const GLenum kFormat3 = GL_RGBA;
const GLsizei kSamples3 = 0;
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id);
scoped_refptr<TextureRef> texture1(
texture_manager_->GetTexture(kTextureClient1Id));
ASSERT_TRUE(texture1.get() != nullptr);
// check adding one attachment
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
// Try format that doesn't work with COLOR_ATTACHMENT0
texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(
texture1.get(), GL_TEXTURE_2D, kLevel1, kBadFormat1, kWidth1, kHeight1,
kDepth, kBorder, kBadFormat1, kType, gfx::Rect(kWidth1, kHeight1));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Try a good format.
texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1,
kFormat1, kWidth1, kHeight1, kDepth, kBorder,
kFormat1, kType, gfx::Rect());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1,
kFormat1, kWidth1, kHeight1, kDepth, kBorder,
kFormat1, kType, gfx::Rect(kWidth1, kHeight1));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(kFormat1),
framebuffer_->GetReadBufferInternalFormat());
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth1, attachment->width());
EXPECT_EQ(kHeight1, attachment->height());
EXPECT_EQ(kSamples1, attachment->samples());
EXPECT_EQ(kFormat1, attachment->internal_format());
EXPECT_TRUE(attachment->cleared());
// Check replacing an attachment
texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id);
scoped_refptr<TextureRef> texture2(
texture_manager_->GetTexture(kTextureClient2Id));
ASSERT_TRUE(texture2.get() != nullptr);
texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel2,
kFormat2, kWidth2, kHeight2, kDepth, kBorder,
kFormat2, kType, gfx::Rect(kWidth2, kHeight2));
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture2.get(), kTarget2, kLevel2, kSamples2);
EXPECT_EQ(static_cast<GLenum>(kFormat2),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth2, attachment->width());
EXPECT_EQ(kHeight2, attachment->height());
EXPECT_EQ(kSamples2, attachment->samples());
EXPECT_EQ(kFormat2, attachment->internal_format());
EXPECT_TRUE(attachment->cleared());
// Check changing attachment
texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3,
kFormat3, kWidth3, kHeight3, kDepth, kBorder,
kFormat3, kType, gfx::Rect());
attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
EXPECT_EQ(kWidth3, attachment->width());
EXPECT_EQ(kHeight3, attachment->height());
EXPECT_EQ(kSamples3, attachment->samples());
EXPECT_EQ(kFormat3, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
EXPECT_EQ(static_cast<GLenum>(kFormat3),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
// Set to size 0
texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3,
kFormat3, 0, 0, kDepth, kBorder, kFormat3,
kType, gfx::Rect());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
// Check removing it.
framebuffer_->AttachTexture(GL_COLOR_ATTACHMENT0, nullptr, 0, 0, 0);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == nullptr);
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
}
TEST_F(FramebufferInfoTest, AttachTextureCube) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
const GLint kDepth = 1;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLsizei kWidth = 16;
const GLsizei kHeight = 16;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGBA;
const GLenum kTarget = GL_TEXTURE_CUBE_MAP;
const GLsizei kSamples = 0;
const GLenum kTexTargets[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X,
GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get());
texture_manager_->SetTarget(texture.get(), kTarget);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), kTexTargets[0], kLevel, kSamples);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
texture_manager_->SetLevelInfo(texture.get(), kTexTargets[0], kLevel,
kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, gfx::Rect(kWidth, kHeight));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(kFormat),
framebuffer_->GetReadBufferInternalFormat());
// Cube incomplete.
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
for (size_t ii = 1; ii < 6; ++ii) {
texture_manager_->SetLevelInfo(texture.get(), kTexTargets[ii], kLevel,
kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, gfx::Rect(kWidth, kHeight));
}
// Cube complete.
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
}
TEST_F(FramebufferInfoTest, AttachTextureLayer) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
const GLint kBorder = 0;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLsizei kWidth = 16;
const GLsizei kHeight = 32;
const GLint kDepth = 2;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGBA;
const GLenum kTarget = GL_TEXTURE_2D_ARRAY;
const GLsizei kLayer = 0;
const GLint kWrongLayer = kDepth;
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get());
framebuffer_->AttachTextureLayer(
GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kWrongLayer);
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
texture_manager_->SetTarget(texture.get(), kTarget);
texture_manager_->SetLevelInfo(texture.get(), kTarget, kLevel,
kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, gfx::Rect());
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
framebuffer_->AttachTextureLayer(
GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kLayer);
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_EQ(static_cast<GLenum>(kFormat),
framebuffer_->GetReadBufferInternalFormat());
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment);
EXPECT_EQ(kWidth, attachment->width());
EXPECT_EQ(kHeight, attachment->height());
EXPECT_EQ(kFormat, attachment->internal_format());
EXPECT_FALSE(attachment->cleared());
}
TEST_F(FramebufferInfoTest, ClearPartiallyClearedAttachments) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_2D, 0, 0);
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
// Not cleared at all.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4,
4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect());
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
// Clear it but nothing happens.
EXPECT_CALL(*decoder_.get(), GetFeatureInfo())
.WillRepeatedly(Return(feature_info_.get()));
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
// Fully cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4,
4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect(0, 0, 4, 4));
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Clear it but nothing happens.
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Partially cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4,
4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect(1, 1, 2, 2));
EXPECT_FALSE(attachment->cleared());
EXPECT_TRUE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
// Now clear it.
EXPECT_CALL(*decoder_.get(), ClearLevel(texture->texture(),
GL_TEXTURE_2D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
_, _, _, _))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.WillOnce(Return(true))
.RetiresOnSaturation();
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
}
TEST_F(FramebufferInfoTest, Clear3DTextureAttachments) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_3D);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_3D, 0, 0);
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
const int kWidth = 4;
const int kHeight = 8;
const int kDepth = 2;
// Fully cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8,
kWidth, kHeight, kDepth,
0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect(0, 0, kWidth, kHeight));
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Clear it but nothing happens.
EXPECT_CALL(*decoder_.get(), GetFeatureInfo())
.WillRepeatedly(Return(feature_info_.get()));
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Not cleared at all.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_3D, 0, GL_RGBA8,
kWidth, kHeight, kDepth,
0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect());
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
// Now clear it.
EXPECT_CALL(*decoder_.get(), ClearLevel3D(texture->texture(),
GL_TEXTURE_3D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
kWidth, kHeight, kDepth))
.WillOnce(Return(true))
.RetiresOnSaturation();
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
}
TEST_F(FramebufferInfoTest, Clear3DOutsideRenderableRange) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_3D);
// Set base level to 1 but attach level 0.
TestHelper::SetTexParameteriWithExpectations(gl_.get(),
error_state_.get(),
texture_manager_.get(),
texture.get(),
GL_TEXTURE_BASE_LEVEL,
1,
GL_NO_ERROR);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_3D, 0, 0);
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
// Level 0 is not cleared at all.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_3D, 0, GL_RGBA, 4,
4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect());
// Level 1 is cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_3D, 1, GL_RGBA, 2,
2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect(0, 0, 2, 2));
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
EXPECT_CALL(*decoder_.get(),
ClearLevel3D(texture->texture(), GL_TEXTURE_3D, 0, GL_RGBA,
GL_UNSIGNED_BYTE, _, _, _))
.WillOnce(Return(true))
.RetiresOnSaturation();
EXPECT_CALL(*decoder_.get(), GetFeatureInfo())
.WillRepeatedly(Return(feature_info_.get()));
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
}
TEST_F(FramebufferInfoTest, ClearIntegerTextureAttachments) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_2D, 0, 0);
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
const int kWidth = 4;
const int kHeight = 8;
// Fully cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8UI,
kWidth, kHeight, 1,
0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,
gfx::Rect(0, 0, kWidth, kHeight));
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Clear it but nothing happens.
EXPECT_CALL(*decoder_.get(), GetFeatureInfo())
.WillRepeatedly(Return(feature_info_.get()));
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Not cleared at all.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8UI,
kWidth, kHeight, 1,
0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,
gfx::Rect());
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
// Now clear it.
EXPECT_CALL(*decoder_.get(), IsCompressedTextureFormat(GL_RGBA8UI))
.WillOnce(Return(false))
.RetiresOnSaturation();
EXPECT_CALL(*decoder_.get(), ClearLevel(texture->texture(),
GL_TEXTURE_2D,
0,
GL_RGBA_INTEGER,
GL_UNSIGNED_BYTE,
0, 0, kWidth, kHeight))
.WillOnce(Return(true))
.RetiresOnSaturation();
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
}
TEST_F(FramebufferInfoTest, ClearIntegerOutsideRenderableRange) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
// Set base level to 1 but attach level 0.
TestHelper::SetTexParameteriWithExpectations(gl_.get(),
error_state_.get(),
texture_manager_.get(),
texture.get(),
GL_TEXTURE_BASE_LEVEL,
1,
GL_NO_ERROR);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_2D, 0, 0);
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
ASSERT_TRUE(attachment != nullptr);
// Level 0 is not cleared at all.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8UI, 4,
4, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,
gfx::Rect());
// Level 1 is cleared.
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 1, GL_RGBA8UI, 2,
2, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE,
gfx::Rect(0, 0, 2, 2));
EXPECT_FALSE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
EXPECT_CALL(*decoder_.get(), IsCompressedTextureFormat(GL_RGBA8UI))
.WillOnce(Return(false))
.RetiresOnSaturation();
EXPECT_CALL(*decoder_.get(),
ClearLevel(texture->texture(), GL_TEXTURE_2D, 0, GL_RGBA_INTEGER,
GL_UNSIGNED_BYTE, _, _, _, _))
.WillOnce(Return(true))
.RetiresOnSaturation();
EXPECT_CALL(*decoder_.get(), GetFeatureInfo())
.WillRepeatedly(Return(feature_info_.get()));
framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
decoder_.get(), texture_manager_.get());
EXPECT_TRUE(attachment->cleared());
EXPECT_FALSE(attachment->IsPartiallyCleared());
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
}
TEST_F(FramebufferInfoTest, DrawBuffers) {
const GLuint kTextureClientId[] = { 33, 34 };
const GLuint kTextureServiceId[] = { 333, 334 };
for (GLenum i = GL_COLOR_ATTACHMENT0;
i < GL_COLOR_ATTACHMENT0 + kMaxColorAttachments; ++i) {
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(i));
}
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
EXPECT_EQ(static_cast<GLenum>(GL_COLOR_ATTACHMENT0),
framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER0_ARB));
for (GLenum i = GL_DRAW_BUFFER1_ARB;
i < GL_DRAW_BUFFER0_ARB + kMaxDrawBuffers; ++i) {
EXPECT_EQ(static_cast<GLenum>(GL_NONE),
framebuffer_->GetDrawBuffer(i));
}
for (size_t ii = 0; ii < arraysize(kTextureClientId); ++ii) {
texture_manager_->CreateTexture(
kTextureClientId[ii], kTextureServiceId[ii]);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId[ii]));
ASSERT_TRUE(texture.get());
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0 + ii, texture.get(), GL_TEXTURE_2D, 0, 0);
EXPECT_FALSE(
framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0 + ii));
const Framebuffer::Attachment* attachment =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0 + ii);
ASSERT_TRUE(attachment);
EXPECT_TRUE(attachment->cleared());
}
EXPECT_TRUE(framebuffer_->IsCleared());
EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments());
// Set draw buffer 1 as uncleared.
scoped_refptr<TextureRef> texture1(
texture_manager_->GetTexture(kTextureClientId[1]));
texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4,
4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
gfx::Rect());
const Framebuffer::Attachment* attachment1 =
framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT1);
ASSERT_TRUE(attachment1);
EXPECT_FALSE(attachment1->cleared());
EXPECT_FALSE(framebuffer_->IsCleared());
EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT1));
EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments());
GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
framebuffer_->SetDrawBuffers(2, buffers);
EXPECT_EQ(static_cast<GLenum>(GL_COLOR_ATTACHMENT0),
framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER0_ARB));
EXPECT_EQ(static_cast<GLenum>(GL_COLOR_ATTACHMENT1),
framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER1_ARB));
for (GLenum i = GL_DRAW_BUFFER2_ARB;
i < GL_DRAW_BUFFER0_ARB + kMaxDrawBuffers; ++i) {
EXPECT_EQ(static_cast<GLenum>(GL_NONE),
framebuffer_->GetDrawBuffer(i));
}
// Only draw buffer 1 needs clearing, so we need to mask draw buffer 0.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(
framebuffer_->PrepareDrawBuffersForClearingUninitializedAttachments());
// Now we disable draw buffer 1.
buffers[1] = GL_NONE;
framebuffer_->SetDrawBuffers(2, buffers);
// We will enable the disabled draw buffer for clear(), and disable it
// after the clear.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(
framebuffer_->PrepareDrawBuffersForClearingUninitializedAttachments());
// Now we disable draw buffer 0, enable draw buffer 1.
buffers[0] = GL_NONE;
buffers[1] = GL_COLOR_ATTACHMENT1;
framebuffer_->SetDrawBuffers(2, buffers);
// This is the perfect setting for clear. No need to call DrawBuffers().
EXPECT_FALSE(
framebuffer_->PrepareDrawBuffersForClearingUninitializedAttachments());
}
TEST_F(FramebufferInfoTest, DrawBufferMasks) {
const GLuint kTextureClientId[] = { 33, 34, 35, 36, 37 };
const GLuint kTextureServiceId[] = { 333, 334, 335, 336, 337 };
const GLenum kAttachment[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT4,
GL_DEPTH_ATTACHMENT};
const GLenum kInternalFormat[] = {
GL_RGBA8,
GL_RG32UI,
GL_R16I,
GL_R16F,
GL_DEPTH_COMPONENT24};
const GLenum kFormat[] = {
GL_RGBA,
GL_RG_INTEGER,
GL_RED_INTEGER,
GL_RED,
GL_DEPTH_COMPONENT};
const GLenum kType[] = {
GL_UNSIGNED_BYTE,
GL_UNSIGNED_INT,
GL_SHORT,
GL_FLOAT,
GL_UNSIGNED_INT};
for (size_t ii = 0; ii < arraysize(kTextureClientId); ++ii) {
texture_manager_->CreateTexture(
kTextureClientId[ii], kTextureServiceId[ii]);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId[ii]));
ASSERT_TRUE(texture.get());
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0,
kInternalFormat[ii], 4, 4, 1, 0,
kFormat[ii], kType[ii], gfx::Rect());
framebuffer_->AttachTexture(
kAttachment[ii], texture.get(), GL_TEXTURE_2D, 0, 0);
ASSERT_TRUE(framebuffer_->GetAttachment(kAttachment[ii]));
}
manager_.MarkAsComplete(framebuffer_);
{ // Default draw buffer settings
EXPECT_EQ(0x3u, framebuffer_->draw_buffer_type_mask());
EXPECT_EQ(0x3u, framebuffer_->draw_buffer_bound_mask());
EXPECT_FALSE(framebuffer_->ContainsActiveIntegerAttachments());
}
{ // Exact draw buffer settings.
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_NONE, GL_COLOR_ATTACHMENT4};
framebuffer_->SetDrawBuffers(5, buffers);
EXPECT_EQ(0x31Bu, framebuffer_->draw_buffer_type_mask());
EXPECT_EQ(0x33Fu, framebuffer_->draw_buffer_bound_mask());
EXPECT_TRUE(framebuffer_->ContainsActiveIntegerAttachments());
}
{ // All disabled draw buffer settings.
GLenum buffers[] = {GL_NONE};
framebuffer_->SetDrawBuffers(1, buffers);
EXPECT_EQ(0u, framebuffer_->draw_buffer_type_mask());
EXPECT_EQ(0u, framebuffer_->draw_buffer_bound_mask());
EXPECT_FALSE(framebuffer_->ContainsActiveIntegerAttachments());
}
{ // Filter out integer buffers.
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE,
GL_COLOR_ATTACHMENT4};
framebuffer_->SetDrawBuffers(5, buffers);
EXPECT_EQ(0x303u, framebuffer_->draw_buffer_type_mask());
EXPECT_EQ(0x303u, framebuffer_->draw_buffer_bound_mask());
EXPECT_FALSE(framebuffer_->ContainsActiveIntegerAttachments());
}
{ // All enabled draw buffer settings.
GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6, GL_COLOR_ATTACHMENT7};
framebuffer_->SetDrawBuffers(8, buffers);
EXPECT_EQ(0x31Bu, framebuffer_->draw_buffer_type_mask());
EXPECT_EQ(0x33Fu, framebuffer_->draw_buffer_bound_mask());
EXPECT_TRUE(framebuffer_->ContainsActiveIntegerAttachments());
}
// Test ValidateAndAdjustDrawBuffers().
// gl_FragColor situation.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(framebuffer_->ValidateAndAdjustDrawBuffers(0x3u, 0x3u));
// gl_FragData situation.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(0);
EXPECT_FALSE(
framebuffer_->ValidateAndAdjustDrawBuffers(0xFFFFFFFFu, 0xFFFFFFFFu));
// User defined output variables, fully match.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(
framebuffer_->ValidateAndAdjustDrawBuffers(0x31Bu, 0x33Fu));
// Call it a second time - this test is critical, making sure we don't
// call DrawBuffers() every draw call if program doesn't change.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(0);
EXPECT_TRUE(
framebuffer_->ValidateAndAdjustDrawBuffers(0x31Bu, 0x33Fu));
// User defined output variables, fully on, one type mismatch.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(0);
EXPECT_FALSE(
framebuffer_->ValidateAndAdjustDrawBuffers(0x32Bu, 0x33Fu));
// Empty output.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(
framebuffer_->ValidateAndAdjustDrawBuffers(0u, 0u));
// User defined output variables, some active buffers have no corresponding
// output variables, but if they do, types match.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(1)
.RetiresOnSaturation();
EXPECT_TRUE(
framebuffer_->ValidateAndAdjustDrawBuffers(0x310u, 0x330u));
// Call it a second time - making sure DrawBuffers isn't triggered.
EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _))
.Times(0);
EXPECT_TRUE(
framebuffer_->ValidateAndAdjustDrawBuffers(0x310u, 0x330u));
}
class FramebufferInfoFloatTest : public FramebufferInfoTestBase {
public:
FramebufferInfoFloatTest()
: FramebufferInfoTestBase(CONTEXT_TYPE_OPENGLES3) {}
~FramebufferInfoFloatTest() override {}
protected:
void SetUp() override {
InitializeContext("OpenGL ES 3.0",
"GL_OES_texture_float GL_EXT_color_buffer_float");
}
};
TEST_F(FramebufferInfoFloatTest, AttachFloatTexture) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
const GLint kDepth = 1;
const GLint kBorder = 0;
const GLenum kType = GL_FLOAT;
const GLsizei kWidth = 16;
const GLsizei kHeight = 32;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGBA;
const GLenum kInternalFormat = GL_RGBA32F;
const GLenum kTarget = GL_TEXTURE_2D;
const GLsizei kSamples = 0;
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kSamples);
EXPECT_EQ(static_cast<GLenum>(0),
framebuffer_->GetReadBufferInternalFormat());
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, kLevel,
kInternalFormat, kWidth, kHeight, kDepth,
kBorder, kFormat, kType, gfx::Rect());
// Texture with a sized float internalformat is allowed as an attachment
// since float color attachment extension is present.
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
}
TEST_F(FramebufferInfoTest, UnbindRenderbuffer) {
const GLuint kRenderbufferClient1Id = 33;
const GLuint kRenderbufferService1Id = 333;
const GLuint kRenderbufferClient2Id = 34;
const GLuint kRenderbufferService2Id = 334;
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient1Id, kRenderbufferService1Id);
Renderbuffer* renderbuffer1 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id);
ASSERT_TRUE(renderbuffer1 != nullptr);
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient2Id, kRenderbufferService2Id);
Renderbuffer* renderbuffer2 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id);
ASSERT_TRUE(renderbuffer2 != nullptr);
// Attach to 2 attachment points.
framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1);
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
// Check they were attached.
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != nullptr);
// Unbind unattached renderbuffer.
framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer2);
// Should be no-op.
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != nullptr);
// Unbind renderbuffer.
framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
// Check they were detached
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == nullptr);
}
TEST_F(FramebufferInfoTest, UnbindTexture) {
const GLuint kTextureClient1Id = 33;
const GLuint kTextureService1Id = 333;
const GLuint kTextureClient2Id = 34;
const GLuint kTextureService2Id = 334;
const GLenum kTarget1 = GL_TEXTURE_2D;
const GLint kLevel1 = 0;
const GLint kSamples1 = 0;
texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id);
scoped_refptr<TextureRef> texture1(
texture_manager_->GetTexture(kTextureClient1Id));
ASSERT_TRUE(texture1.get() != nullptr);
texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id);
scoped_refptr<TextureRef> texture2(
texture_manager_->GetTexture(kTextureClient2Id));
ASSERT_TRUE(texture2.get() != nullptr);
// Attach to 2 attachment points.
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1);
framebuffer_->AttachTexture(
GL_DEPTH_ATTACHMENT, texture1.get(), kTarget1, kLevel1, kSamples1);
// Check they were attached.
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != nullptr);
// Unbind unattached texture.
framebuffer_->UnbindTexture(kTarget1, texture2.get());
// Should be no-op.
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != nullptr);
// Unbind texture.
framebuffer_->UnbindTexture(kTarget1, texture1.get());
// Check they were detached
EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == nullptr);
EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == nullptr);
}
TEST_F(FramebufferInfoTest, IsCompleteMarkAsComplete) {
const GLuint kRenderbufferClient1Id = 33;
const GLuint kRenderbufferService1Id = 333;
const GLuint kTextureClient2Id = 34;
const GLuint kTextureService2Id = 334;
const GLenum kTarget1 = GL_TEXTURE_2D;
const GLint kLevel1 = 0;
const GLint kSamples1 = 0;
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient1Id, kRenderbufferService1Id);
Renderbuffer* renderbuffer1 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id);
ASSERT_TRUE(renderbuffer1 != nullptr);
texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id);
scoped_refptr<TextureRef> texture2(
texture_manager_->GetTexture(kTextureClient2Id));
ASSERT_TRUE(texture2.get() != nullptr);
// Check MarkAsComlete marks as complete.
manager_.MarkAsComplete(framebuffer_);
EXPECT_TRUE(manager_.IsComplete(framebuffer_));
// Check at attaching marks as not complete.
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1);
EXPECT_FALSE(manager_.IsComplete(framebuffer_));
manager_.MarkAsComplete(framebuffer_);
EXPECT_TRUE(manager_.IsComplete(framebuffer_));
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
EXPECT_FALSE(manager_.IsComplete(framebuffer_));
// Check MarkAttachmentsAsCleared marks as complete.
manager_.MarkAttachmentsAsCleared(
framebuffer_, renderbuffer_manager_.get(), texture_manager_.get());
EXPECT_TRUE(manager_.IsComplete(framebuffer_));
// Check Unbind marks as not complete.
framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
EXPECT_FALSE(manager_.IsComplete(framebuffer_));
manager_.MarkAsComplete(framebuffer_);
EXPECT_TRUE(manager_.IsComplete(framebuffer_));
framebuffer_->UnbindTexture(kTarget1, texture2.get());
EXPECT_FALSE(manager_.IsComplete(framebuffer_));
}
TEST_F(FramebufferInfoTest, GetStatus) {
const GLuint kRenderbufferClient1Id = 33;
const GLuint kRenderbufferService1Id = 333;
const GLuint kTextureClient2Id = 34;
const GLuint kTextureService2Id = 334;
const GLenum kTarget1 = GL_TEXTURE_2D;
const GLint kLevel1 = 0;
const GLint kSamples1 = 0;
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient1Id, kRenderbufferService1Id);
Renderbuffer* renderbuffer1 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id);
ASSERT_TRUE(renderbuffer1 != nullptr);
texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id);
scoped_refptr<TextureRef> texture2(
texture_manager_->GetTexture(kTextureClient2Id));
ASSERT_TRUE(texture2.get() != nullptr);
texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D);
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
.RetiresOnSaturation();
framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER);
// Check a second call for the same type does not call anything
framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER);
// Check changing the attachments calls CheckFramebufferStatus.
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1);
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)).RetiresOnSaturation();
framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER);
// Check a second call for the same type does not call anything.
framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER);
// Check a second call with a different target calls CheckFramebufferStatus.
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
.RetiresOnSaturation();
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check a second call for the same type does not call anything.
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check adding another attachment calls CheckFramebufferStatus.
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
.RetiresOnSaturation();
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check a second call for the same type does not call anything.
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check changing the format calls CheckFramebuffferStatus.
TestHelper::SetTexParameteriWithExpectations(gl_.get(),
error_state_.get(),
texture_manager_.get(),
texture2.get(),
GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE,
GL_NO_ERROR);
EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
.WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT))
.WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
.RetiresOnSaturation();
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check since it did not return FRAMEBUFFER_COMPLETE that it calls
// CheckFramebufferStatus
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check putting it back does not call CheckFramebufferStatus.
TestHelper::SetTexParameteriWithExpectations(gl_.get(),
error_state_.get(),
texture_manager_.get(),
texture2.get(),
GL_TEXTURE_WRAP_S,
GL_REPEAT,
GL_NO_ERROR);
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
// Check Unbinding does not call CheckFramebufferStatus
framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER);
}
class FramebufferInfoES3Test : public FramebufferInfoTestBase {
public:
FramebufferInfoES3Test() : FramebufferInfoTestBase(CONTEXT_TYPE_WEBGL2) {}
protected:
void SetUp() override {
InitializeContext("OpenGL ES 3.0", "");
}
};
TEST_F(FramebufferInfoES3Test, DifferentDimensions) {
const GLuint kRenderbufferClient1Id = 33;
const GLuint kRenderbufferService1Id = 333;
const GLuint kRenderbufferClient2Id = 34;
const GLuint kRenderbufferService2Id = 334;
const GLsizei kWidth1 = 16;
const GLsizei kHeight1 = 32;
const GLenum kFormat1 = GL_RGBA4;
const GLsizei kSamples1 = 0;
const GLsizei kWidth2 = 32; // Different from kWidth1
const GLsizei kHeight2 = 32;
const GLenum kFormat2 = GL_DEPTH_COMPONENT16;
const GLsizei kSamples2 = 0;
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient1Id, kRenderbufferService1Id);
Renderbuffer* renderbuffer1 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id);
ASSERT_TRUE(renderbuffer1 != nullptr);
renderbuffer_manager_->SetInfo(
renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1);
framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1);
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClient2Id, kRenderbufferService2Id);
Renderbuffer* renderbuffer2 =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id);
ASSERT_TRUE(renderbuffer2 != nullptr);
renderbuffer_manager_->SetInfo(
renderbuffer2, kSamples2, kFormat2, kWidth2, kHeight2);
framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer2);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
}
TEST_F(FramebufferInfoES3Test, DuplicatedAttachments) {
const GLuint kTextureClientId = 33;
const GLuint kTextureServiceId = 333;
const GLenum kTarget = GL_TEXTURE_2D;
const GLint kLevel = 0;
const GLenum kFormat = GL_RGBA;
const GLenum kType = GL_UNSIGNED_BYTE;
const GLint kWidth = 16;
const GLint kHeight = 32;
const GLint kDepth = 1;
const GLint kBorder = 0;
const GLint kSamples = 0;
texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId);
scoped_refptr<TextureRef> texture(
texture_manager_->GetTexture(kTextureClientId));
ASSERT_TRUE(texture.get() != nullptr);
texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D);
texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, kLevel,
kFormat, kWidth, kHeight, kDepth, kBorder,
kFormat, kType, gfx::Rect());
// Check an image is attached to more than one color attachment point
// in a framebuffer.
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kSamples);
framebuffer_->AttachTexture(
GL_COLOR_ATTACHMENT1, texture.get(), kTarget, kLevel, kSamples);
EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_UNSUPPORTED),
framebuffer_->IsPossiblyComplete(feature_info_.get()));
}
TEST_F(FramebufferInfoES3Test, ReadBuffer) {
const GLuint kRenderbufferClientId = 33;
const GLuint kRenderbufferServiceId = 333;
EXPECT_EQ(static_cast<GLenum>(GL_COLOR_ATTACHMENT0),
framebuffer_->read_buffer());
framebuffer_->set_read_buffer(GL_NONE);
EXPECT_EQ(static_cast<GLenum>(GL_NONE), framebuffer_->read_buffer());
EXPECT_FALSE(framebuffer_->GetReadBufferAttachment());
framebuffer_->set_read_buffer(GL_COLOR_ATTACHMENT1);
EXPECT_FALSE(framebuffer_->GetReadBufferAttachment());
renderbuffer_manager_->CreateRenderbuffer(
kRenderbufferClientId, kRenderbufferServiceId);
Renderbuffer* renderbuffer =
renderbuffer_manager_->GetRenderbuffer(kRenderbufferClientId);
ASSERT_TRUE(renderbuffer != nullptr);
framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT1, renderbuffer);
EXPECT_TRUE(framebuffer_->GetReadBufferAttachment());
}
} // namespace gles2
} // namespace gpu