blob: 6f21d120f66a6b7e2127fc2ce763a7c49e844745 [file] [log] [blame]
// Copyright 2016 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 "chrome/browser/android/vr_shell/vr_shell_renderer.h"
#include "chrome/browser/android/vr_shell/vr_util.h"
#include "ui/gl/gl_bindings.h"
namespace vr_shell {
namespace {
const float kHalfHeight = 0.5f;
const float kHalfWidth = 0.5f;
const float kTextureQuadPosition[18] = {
-kHalfWidth, kHalfHeight, 0.0f, -kHalfWidth, -kHalfHeight, 0.0f,
kHalfWidth, kHalfHeight, 0.0f, -kHalfWidth, -kHalfHeight, 0.0f,
kHalfWidth, -kHalfHeight, 0.0f, kHalfWidth, kHalfHeight, 0.0f};
const int kPositionDataSize = 3;
// Number of vertices passed to glDrawArrays().
const int kVerticesNumber = 6;
const float kTexturedQuadTextureCoordinates[12] = {
0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f};
const int kTextureCoordinateDataSize = 2;
const float kWebVrVertices[32] = {
// x y u, v
-1.f, 1.f, 0.f, 0.f, // Left Eye
-1.f, -1.f, 0.f, 1.f,
0.f, -1.f, 1.f, 1.f,
0.f, 1.f, 1.f, 0.f,
0.f, 1.f, 0.f, 0.f, // Right Eye
0.f, -1.f, 0.f, 1.f,
1.f, -1.f, 1.f, 1.f,
1.f, 1.f, 1.f, 0.f };
const int kWebVrVerticesSize = sizeof(float) * 32;
#define SHADER(Src) #Src
#define OEIE_SHADER(Src) "#extension GL_OES_EGL_image_external : require\n" #Src
#define VOID_OFFSET(x) reinterpret_cast<void*>(x)
const char* GetShaderSource(ShaderID shader) {
switch (shader) {
case TEXTURE_QUAD_VERTEX_SHADER:
return SHADER(uniform mat4 u_CombinedMatrix; attribute vec4 a_Position;
attribute vec2 a_TexCoordinate;
varying vec2 v_TexCoordinate; void main() {
v_TexCoordinate = a_TexCoordinate;
gl_Position = u_CombinedMatrix * a_Position;
});
case TEXTURE_QUAD_FRAGMENT_SHADER:
return OEIE_SHADER(
precision highp float; uniform samplerExternalOES u_Texture;
varying vec2 v_TexCoordinate; void main() {
vec4 texture = texture2D(u_Texture, v_TexCoordinate);
gl_FragColor = vec4(texture.r, texture.g, texture.b, 1.0);
});
case vr_shell::ShaderID::WEBVR_VERTEX_SHADER:
return SHADER(
attribute vec2 a_Position;
attribute vec2 a_TexCoordinate;
uniform vec4 u_SrcRect;
varying vec2 v_TexCoordinate;
void main() {
v_TexCoordinate = u_SrcRect.xy + (a_TexCoordinate * u_SrcRect.zw);
gl_Position = vec4(a_Position, 0.0, 1.0);
});
case vr_shell::ShaderID::WEBVR_FRAGMENT_SHADER:
return OEIE_SHADER(
precision highp float;
uniform samplerExternalOES u_Texture;
varying vec2 v_TexCoordinate;
void main() {
gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
});
default:
LOG(ERROR) << "Shader source requested for unknown shader";
return "";
}
}
} // namespace
TexturedQuadRenderer::TexturedQuadRenderer() {
std::string error;
vertex_shader_handle_ = CompileShader(
GL_VERTEX_SHADER, GetShaderSource(TEXTURE_QUAD_VERTEX_SHADER), error);
CHECK(vertex_shader_handle_) << error;
fragment_shader_handle_ = CompileShader(
GL_FRAGMENT_SHADER, GetShaderSource(TEXTURE_QUAD_FRAGMENT_SHADER), error);
CHECK(fragment_shader_handle_) << error;
program_handle_ = CreateAndLinkProgram(
vertex_shader_handle_, fragment_shader_handle_, 4, nullptr, error);
CHECK(program_handle_) << error;
combined_matrix_handle_ =
glGetUniformLocation(program_handle_, "u_CombinedMatrix");
texture_uniform_handle_ = glGetUniformLocation(program_handle_, "u_Texture");
position_handle_ = glGetAttribLocation(program_handle_, "a_Position");
texture_coordinate_handle_ =
glGetAttribLocation(program_handle_, "a_TexCoordinate");
}
void TexturedQuadRenderer::Draw(int texture_data_handle,
const gvr::Mat4f& combined_matrix) {
glUseProgram(program_handle_);
// Pass in model view project matrix.
glUniformMatrix4fv(combined_matrix_handle_, 1, false,
MatrixToGLArray(combined_matrix).data());
// Pass in texture coordinate.
glVertexAttribPointer(texture_coordinate_handle_, kTextureCoordinateDataSize,
GL_FLOAT, false, 0, kTexturedQuadTextureCoordinates);
glEnableVertexAttribArray(texture_coordinate_handle_);
glVertexAttribPointer(position_handle_, kPositionDataSize, GL_FLOAT, false, 0,
kTextureQuadPosition);
glEnableVertexAttribArray(position_handle_);
// Link texture data with texture unit.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_data_handle);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glUniform1i(texture_uniform_handle_, 0);
glDrawArrays(GL_TRIANGLES, 0, kVerticesNumber);
glDisableVertexAttribArray(position_handle_);
glDisableVertexAttribArray(texture_coordinate_handle_);
}
TexturedQuadRenderer::~TexturedQuadRenderer() {
glDeleteShader(vertex_shader_handle_);
glDeleteShader(fragment_shader_handle_);
}
WebVrRenderer::WebVrRenderer() {
left_bounds_ = { 0.0f, 0.0f, 0.5f, 1.0f };
right_bounds_ = { 0.5f, 0.0f, 0.5f, 1.0f };
std::string error;
GLuint vertex_shader_handle = CompileShader(
GL_VERTEX_SHADER, GetShaderSource(WEBVR_VERTEX_SHADER), error);
CHECK(vertex_shader_handle) << error;
GLuint fragment_shader_handle = CompileShader(
GL_FRAGMENT_SHADER, GetShaderSource(WEBVR_FRAGMENT_SHADER), error);
CHECK(fragment_shader_handle) << error;
program_handle_ = CreateAndLinkProgram(
vertex_shader_handle, fragment_shader_handle, 2, nullptr, error);
CHECK(program_handle_) << error;
// Once the program is linked the shader objects are no longer needed
glDeleteShader(vertex_shader_handle);
glDeleteShader(fragment_shader_handle);
tex_uniform_handle_ = glGetUniformLocation(program_handle_, "u_Texture");
src_rect_uniform_handle_ = glGetUniformLocation(program_handle_, "u_SrcRect");
position_handle_ = glGetAttribLocation(program_handle_, "a_Position");
texcoord_handle_ = glGetAttribLocation(program_handle_, "a_TexCoordinate");
// TODO(bajones): Figure out why this need to be restored.
GLint old_buffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &old_buffer);
glGenBuffersARB(1, &vertex_buffer_);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBufferData(GL_ARRAY_BUFFER, kWebVrVerticesSize, kWebVrVertices,
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, old_buffer);
}
// Draw the stereo WebVR frame
void WebVrRenderer::Draw(int texture_handle) {
// TODO(bajones): Figure out why this need to be restored.
GLint old_buffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &old_buffer);
glUseProgram(program_handle_);
// Bind vertex attributes
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glEnableVertexAttribArray(position_handle_);
glEnableVertexAttribArray(texcoord_handle_);
glVertexAttribPointer(position_handle_, POSITION_ELEMENTS, GL_FLOAT, false,
VERTEX_STRIDE, VOID_OFFSET(POSITION_OFFSET));
glVertexAttribPointer(texcoord_handle_, TEXCOORD_ELEMENTS, GL_FLOAT, false,
VERTEX_STRIDE, VOID_OFFSET(TEXCOORD_OFFSET));
// Bind texture.
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_handle);
glUniform1i(tex_uniform_handle_, 0);
// TODO(bajones): Should be able handle both eyes in a single draw call.
// Left eye
glUniform4fv(src_rect_uniform_handle_, 1, (float*)(&left_bounds_));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Right eye
glUniform4fv(src_rect_uniform_handle_, 1, (float*)(&right_bounds_));
glDrawArrays(GL_TRIANGLE_FAN, 4, 4);
glDisableVertexAttribArray(position_handle_);
glDisableVertexAttribArray(texcoord_handle_);
glBindBuffer(GL_ARRAY_BUFFER, old_buffer);
}
void WebVrRenderer::UpdateTextureBounds(int eye, const gvr::Rectf& bounds) {
if (eye == 0) {
left_bounds_ = bounds;
} else if (eye == 1) {
right_bounds_ = bounds;
}
}
WebVrRenderer::~WebVrRenderer() {
glDeleteBuffersARB(1, &vertex_buffer_);
glDeleteProgram(program_handle_);
}
VrShellRenderer::VrShellRenderer()
: textured_quad_renderer_(new TexturedQuadRenderer),
webvr_renderer_(new WebVrRenderer) {}
VrShellRenderer::~VrShellRenderer() {}
} // namespace vr_shell