1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "device/vr/android/arcore/ar_renderer.h"
6 
7 #include "base/stl_util.h"
8 #include "device/vr/vr_gl_util.h"
9 
10 namespace device {
11 
12 namespace {
13 
14 static constexpr float kQuadVertices[8] = {
15     -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, -0.5f,
16 };
17 static constexpr GLushort kQuadIndices[6] = {0, 1, 2, 1, 3, 2};
18 
19 // clang-format off
20 static constexpr char const* kVertexShader = SHADER(
21   precision mediump float;
22   uniform mat4 u_UvTransform;
23   attribute vec4 a_Position;
24   varying vec2 v_TexCoordinate;
25 
26   void main() {
27     // The quad vertex coordinate range is [-0.5, 0.5]. Transform to [0, 1],
28     // then apply the supplied affine transform matrix to get the final UV.
29     float xposition = a_Position[0] + 0.5;
30     float yposition = a_Position[1] + 0.5;
31     vec4 uv_in = vec4(xposition, yposition, 0.0, 1.0);
32     vec4 uv_out = u_UvTransform * uv_in;
33     v_TexCoordinate = vec2(uv_out.x, uv_out.y);
34     gl_Position = vec4(a_Position.xyz * 2.0, 1.0);
35   }
36 );
37 
38 static constexpr char const* kFragmentShader = OEIE_SHADER(
39   precision highp float;
40   uniform samplerExternalOES u_Texture;
41   varying vec2 v_TexCoordinate;
42 
43   void main() {
44     gl_FragColor = texture2D(u_Texture, v_TexCoordinate);
45   }
46 );
47 // clang-format on
48 
49 }  // namespace
50 
ArRenderer()51 ArRenderer::ArRenderer() {
52   std::string error;
53   GLuint vertex_shader_handle =
54       vr::CompileShader(GL_VERTEX_SHADER, kVertexShader, error);
55   // TODO(crbug.com/866593): fail gracefully if shaders don't compile.
56   CHECK(vertex_shader_handle) << error << "\nvertex_src\n" << kVertexShader;
57 
58   GLuint fragment_shader_handle =
59       vr::CompileShader(GL_FRAGMENT_SHADER, kFragmentShader, error);
60   CHECK(fragment_shader_handle) << error << "\nfragment_src\n"
61                                 << kFragmentShader;
62 
63   program_handle_ = vr::CreateAndLinkProgram(vertex_shader_handle,
64                                              fragment_shader_handle, error);
65   CHECK(program_handle_) << error;
66 
67   // Once the program is linked the shader objects are no longer needed
68   glDeleteShader(vertex_shader_handle);
69   glDeleteShader(fragment_shader_handle);
70 
71   position_handle_ = glGetAttribLocation(program_handle_, "a_Position");
72   clip_rect_handle_ = glGetUniformLocation(program_handle_, "u_ClipRect");
73   texture_handle_ = glGetUniformLocation(program_handle_, "u_Texture");
74   uv_transform_ = glGetUniformLocation(program_handle_, "u_UvTransform");
75 }
76 
Draw(int texture_handle,const float (& uv_transform)[16])77 void ArRenderer::Draw(int texture_handle, const float (&uv_transform)[16]) {
78   if (!vertex_buffer_ || !index_buffer_) {
79     GLuint buffers[2];
80     glGenBuffersARB(2, buffers);
81     vertex_buffer_ = buffers[0];
82     index_buffer_ = buffers[1];
83 
84     glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
85     glBufferData(GL_ARRAY_BUFFER, base::size(kQuadVertices) * sizeof(float),
86                  kQuadVertices, GL_STATIC_DRAW);
87 
88     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
89     glBufferData(GL_ELEMENT_ARRAY_BUFFER,
90                  base::size(kQuadIndices) * sizeof(GLushort), kQuadIndices,
91                  GL_STATIC_DRAW);
92   }
93 
94   glUseProgram(program_handle_);
95 
96   // Bind vertex attributes
97   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
98 
99   // Set up position attribute.
100   glVertexAttribPointer(position_handle_, 2, GL_FLOAT, false, 0, 0);
101   glEnableVertexAttribArray(position_handle_);
102 
103   // Bind texture. This is not necessarily a 1:1 pixel copy since the
104   // size is modified by framebufferScaleFactor and requestViewportScale,
105   // so use GL_LINEAR.
106   glActiveTexture(GL_TEXTURE0);
107   glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_handle);
108   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
109   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
110   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
111   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
112   glUniform1i(texture_handle_, 0);
113 
114   glUniformMatrix4fv(uv_transform_, 1, GL_FALSE, &uv_transform[0]);
115 
116   // Blit texture to buffer
117   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
118   glDrawElements(GL_TRIANGLES, base::size(kQuadIndices), GL_UNSIGNED_SHORT, 0);
119 
120   glDisableVertexAttribArray(position_handle_);
121 }
122 
123 // Note that we don't explicitly delete gl objects here, they're deleted
124 // automatically when we call ShutdownGL, and deleting them here leads to
125 // segfaults.
126 ArRenderer::~ArRenderer() = default;
127 
128 }  // namespace device
129