199 lines
7.0 KiB
C++
199 lines
7.0 KiB
C++
#include <mbgl/test/util.hpp>
|
|
|
|
#include <mbgl/platform/gl_functions.hpp>
|
|
#include <mbgl/gfx/backend_scope.hpp>
|
|
#include <mbgl/gfx/render_pass.hpp>
|
|
#include <mbgl/gl/context.hpp>
|
|
#include <mbgl/gl/texture.hpp>
|
|
#include <mbgl/gl/defines.hpp>
|
|
#include <mbgl/gl/renderable_resource.hpp>
|
|
#include <mbgl/gl/headless_backend.hpp>
|
|
#include <mbgl/gl/offscreen_texture.hpp>
|
|
|
|
|
|
using namespace mbgl;
|
|
using namespace mbgl::platform;
|
|
|
|
TEST(OffscreenTexture, EmptyRed) {
|
|
if (gfx::Backend::GetType() != gfx::Backend::Type::OpenGL) {
|
|
return;
|
|
}
|
|
|
|
gl::HeadlessBackend backend({ 512, 256 });
|
|
gfx::BackendScope scope { backend };
|
|
|
|
// Scissor test shouldn't leak after gl::HeadlessBackend::bind().
|
|
MBGL_CHECK_ERROR(glScissor(64, 64, 128, 128));
|
|
static_cast<gl::Context&>(backend.getContext()).scissorTest.setCurrentValue(true);
|
|
|
|
backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind();
|
|
|
|
MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
|
|
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
|
|
|
|
auto image = backend.readStillImage();
|
|
test::checkImage("test/fixtures/offscreen_texture/empty-red", image, 0, 0);
|
|
}
|
|
|
|
struct Shader {
|
|
Shader(const GLchar* vertex, const GLchar* fragment) {
|
|
program = MBGL_CHECK_ERROR(glCreateProgram());
|
|
vertexShader = MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER));
|
|
fragmentShader = MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER));
|
|
MBGL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertex, nullptr));
|
|
MBGL_CHECK_ERROR(glCompileShader(vertexShader));
|
|
MBGL_CHECK_ERROR(glAttachShader(program, vertexShader));
|
|
MBGL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragment, nullptr));
|
|
MBGL_CHECK_ERROR(glCompileShader(fragmentShader));
|
|
MBGL_CHECK_ERROR(glAttachShader(program, fragmentShader));
|
|
MBGL_CHECK_ERROR(glLinkProgram(program));
|
|
a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
|
|
}
|
|
|
|
~Shader() {
|
|
MBGL_CHECK_ERROR(glDetachShader(program, vertexShader));
|
|
MBGL_CHECK_ERROR(glDetachShader(program, fragmentShader));
|
|
MBGL_CHECK_ERROR(glDeleteShader(vertexShader));
|
|
MBGL_CHECK_ERROR(glDeleteShader(fragmentShader));
|
|
MBGL_CHECK_ERROR(glDeleteProgram(program));
|
|
}
|
|
|
|
GLuint program = 0;
|
|
GLuint vertexShader = 0;
|
|
GLuint fragmentShader = 0;
|
|
GLuint a_pos = 0;
|
|
};
|
|
|
|
struct Buffer {
|
|
Buffer(std::vector<GLfloat> data) {
|
|
MBGL_CHECK_ERROR(glGenBuffers(1, &buffer));
|
|
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer));
|
|
MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(GLfloat), data.data(),
|
|
GL_STATIC_DRAW));
|
|
}
|
|
|
|
~Buffer() {
|
|
MBGL_CHECK_ERROR(glDeleteBuffers(1, &buffer));
|
|
}
|
|
|
|
GLuint buffer = 0;
|
|
};
|
|
|
|
|
|
TEST(OffscreenTexture, RenderToTexture) {
|
|
if (gfx::Backend::GetType() != gfx::Backend::Type::OpenGL) {
|
|
return;
|
|
}
|
|
|
|
gl::HeadlessBackend backend({ 512, 256 });
|
|
gfx::BackendScope scope { backend };
|
|
auto& context = static_cast<gl::Context&>(backend.getContext());
|
|
|
|
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
|
|
MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
|
|
Shader paintShader(R"MBGL_SHADER(
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
attribute vec2 a_pos;
|
|
void main() {
|
|
gl_Position = vec4(a_pos, 0, 1);
|
|
}
|
|
)MBGL_SHADER", R"MBGL_SHADER(
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
void main() {
|
|
gl_FragColor = vec4(0, 0.8, 0, 0.8);
|
|
}
|
|
)MBGL_SHADER");
|
|
|
|
Shader compositeShader(R"MBGL_SHADER(
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
attribute vec2 a_pos;
|
|
varying vec2 v_texcoord;
|
|
void main() {
|
|
gl_Position = vec4(a_pos, 0, 1);
|
|
v_texcoord = (a_pos + 1.0) / 2.0;
|
|
}
|
|
)MBGL_SHADER", R"MBGL_SHADER(
|
|
#ifdef GL_ES
|
|
precision mediump float;
|
|
#endif
|
|
uniform sampler2D u_texture;
|
|
varying vec2 v_texcoord;
|
|
void main() {
|
|
gl_FragColor = texture2D(u_texture, v_texcoord);
|
|
}
|
|
)MBGL_SHADER");
|
|
|
|
GLuint u_texture = MBGL_CHECK_ERROR(glGetUniformLocation(compositeShader.program, "u_texture"));
|
|
|
|
Buffer triangleBuffer({ 0, 0.5, 0.5, -0.5, -0.5, -0.5 });
|
|
Buffer viewportBuffer({ -1, -1, 1, -1, -1, 1, 1, 1 });
|
|
|
|
backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind();
|
|
|
|
// First, draw red to the bound FBO.
|
|
context.clear(Color::red(), {}, {});
|
|
|
|
// Then, create a texture, bind it, and render yellow to that texture. This should not
|
|
// affect the originally bound FBO.
|
|
gl::OffscreenTexture texture(context, { 128, 128 });
|
|
|
|
// Scissor test shouldn't leak after OffscreenTexture::bind().
|
|
MBGL_CHECK_ERROR(glScissor(32, 32, 64, 64));
|
|
context.scissorTest.setCurrentValue(true);
|
|
|
|
texture.getResource<gl::RenderableResource>().bind();
|
|
|
|
context.clear(Color(), {}, {});
|
|
|
|
MBGL_CHECK_ERROR(glUseProgram(paintShader.program));
|
|
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, triangleBuffer.buffer));
|
|
MBGL_CHECK_ERROR(glEnableVertexAttribArray(paintShader.a_pos));
|
|
MBGL_CHECK_ERROR(
|
|
glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
|
|
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3));
|
|
|
|
auto image = texture.readStillImage();
|
|
test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
|
|
|
|
// Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
|
|
backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind();
|
|
|
|
image = backend.readStillImage();
|
|
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
|
|
|
|
// Now, composite the Framebuffer texture we've rendered to onto the main FBO.
|
|
gl::bindTexture(context, 0, { texture.getTexture().getResource(), gfx::TextureFilterType::Linear });
|
|
MBGL_CHECK_ERROR(glUseProgram(compositeShader.program));
|
|
MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
|
|
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));
|
|
MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos));
|
|
MBGL_CHECK_ERROR(
|
|
glVertexAttribPointer(compositeShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
|
|
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));
|
|
|
|
image = backend.readStillImage();
|
|
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo-composited", image, 0, 0.1);
|
|
}
|
|
|
|
TEST(OffscreenTexture, ClearRenderPassColor) {
|
|
auto backend = gfx::HeadlessBackend::Create({ 128, 256 });
|
|
gfx::BackendScope scope { *backend->getRendererBackend() };
|
|
auto& context = backend->getRendererBackend()->getContext();
|
|
auto encoder = context.createCommandEncoder();
|
|
auto offscreenTexture = context.createOffscreenTexture({128, 256}, gfx::TextureChannelDataType::UnsignedByte);
|
|
auto renderPass = encoder->createRenderPass(
|
|
"offscreen texture", { *offscreenTexture, Color{ 1.0f, 0.0f, 0.0f, 1.0f }, {}, {} });
|
|
renderPass.reset();
|
|
encoder.reset();
|
|
|
|
auto image = offscreenTexture->readStillImage();
|
|
test::checkImage("test/fixtures/offscreen_texture/clear-render-pass-color", image, 0, 0);
|
|
}
|