1 /*
2  *  Copyright 2018 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc;
12 
13 import static org.junit.Assert.assertEquals;
14 import static org.mockito.Mockito.mock;
15 import static org.mockito.Mockito.times;
16 import static org.mockito.Mockito.verify;
17 import static org.mockito.Mockito.verifyNoMoreInteractions;
18 
19 import org.chromium.testing.local.LocalRobolectricTestRunner;
20 import org.junit.After;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.junit.runner.RunWith;
24 import org.robolectric.annotation.Config;
25 import org.webrtc.GlShader;
26 
27 @RunWith(LocalRobolectricTestRunner.class)
28 @Config(manifest = Config.NONE)
29 public class GlGenericDrawerTest {
30   // Simplest possible valid generic fragment shader.
31   private static final String FRAGMENT_SHADER = "void main() {\n"
32       + "  gl_FragColor = sample(tc);\n"
33       + "}\n";
34   private static final int TEXTURE_ID = 3;
35   private static final float[] TEX_MATRIX =
36       new float[] {1, 2, 3, 4, -1, -2, -3, -4, 0, 0, 1, 0, 0, 0, 0, 1};
37   private static final int FRAME_WIDTH = 640;
38   private static final int FRAME_HEIGHT = 480;
39   private static final int VIEWPORT_X = 3;
40   private static final int VIEWPORT_Y = 5;
41   private static final int VIEWPORT_WIDTH = 500;
42   private static final int VIEWPORT_HEIGHT = 500;
43 
44   // Replace OpenGLES GlShader dependency with a mock.
45   private class GlGenericDrawerForTest extends GlGenericDrawer {
GlGenericDrawerForTest(String genericFragmentSource, ShaderCallbacks shaderCallbacks)46     public GlGenericDrawerForTest(String genericFragmentSource, ShaderCallbacks shaderCallbacks) {
47       super(genericFragmentSource, shaderCallbacks);
48     }
49 
50     @Override
createShader(ShaderType shaderType)51     GlShader createShader(ShaderType shaderType) {
52       return mockedShader;
53     }
54   }
55 
56   private GlShader mockedShader;
57   private GlGenericDrawer glGenericDrawer;
58   private GlGenericDrawer.ShaderCallbacks mockedCallbacks;
59 
60   @Before
setUp()61   public void setUp() {
62     mockedShader = mock(GlShader.class);
63     mockedCallbacks = mock(GlGenericDrawer.ShaderCallbacks.class);
64     glGenericDrawer = new GlGenericDrawerForTest(FRAGMENT_SHADER, mockedCallbacks);
65   }
66 
67   @After
tearDown()68   public void tearDown() {
69     verifyNoMoreInteractions(mockedCallbacks);
70   }
71 
72   @Test
testOesFragmentShader()73   public void testOesFragmentShader() {
74     final String expectedOesFragmentShader = "#extension GL_OES_EGL_image_external : require\n"
75         + "precision mediump float;\n"
76         + "varying vec2 tc;\n"
77         + "uniform samplerExternalOES tex;\n"
78         + "void main() {\n"
79         + "  gl_FragColor = texture2D(tex, tc);\n"
80         + "}\n";
81     final String oesFragmentShader =
82         GlGenericDrawer.createFragmentShaderString(FRAGMENT_SHADER, GlGenericDrawer.ShaderType.OES);
83     assertEquals(expectedOesFragmentShader, oesFragmentShader);
84   }
85 
86   @Test
testRgbFragmentShader()87   public void testRgbFragmentShader() {
88     final String expectedRgbFragmentShader = "precision mediump float;\n"
89         + "varying vec2 tc;\n"
90         + "uniform sampler2D tex;\n"
91         + "void main() {\n"
92         + "  gl_FragColor = texture2D(tex, tc);\n"
93         + "}\n";
94     final String rgbFragmentShader =
95         GlGenericDrawer.createFragmentShaderString(FRAGMENT_SHADER, GlGenericDrawer.ShaderType.RGB);
96     assertEquals(expectedRgbFragmentShader, rgbFragmentShader);
97   }
98 
99   @Test
testYuvFragmentShader()100   public void testYuvFragmentShader() {
101     final String expectedYuvFragmentShader = "precision mediump float;\n"
102         + "varying vec2 tc;\n"
103         + "uniform sampler2D y_tex;\n"
104         + "uniform sampler2D u_tex;\n"
105         + "uniform sampler2D v_tex;\n"
106         + "vec4 sample(vec2 p) {\n"
107         + "  float y = texture2D(y_tex, p).r * 1.16438;\n"
108         + "  float u = texture2D(u_tex, p).r;\n"
109         + "  float v = texture2D(v_tex, p).r;\n"
110         + "  return vec4(y + 1.59603 * v - 0.874202,\n"
111         + "    y - 0.391762 * u - 0.812968 * v + 0.531668,\n"
112         + "    y + 2.01723 * u - 1.08563, 1);\n"
113         + "}\n"
114         + "void main() {\n"
115         + "  gl_FragColor = sample(tc);\n"
116         + "}\n";
117     final String yuvFragmentShader =
118         GlGenericDrawer.createFragmentShaderString(FRAGMENT_SHADER, GlGenericDrawer.ShaderType.YUV);
119     assertEquals(expectedYuvFragmentShader, yuvFragmentShader);
120   }
121 
122   @Test
testShaderCallbacksOneRgbFrame()123   public void testShaderCallbacksOneRgbFrame() {
124     glGenericDrawer.drawRgb(TEXTURE_ID, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_X,
125         VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
126 
127     verify(mockedCallbacks).onNewShader(mockedShader);
128     verify(mockedCallbacks)
129         .onPrepareShader(
130             mockedShader, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
131   }
132 
133   @Test
testShaderCallbacksTwoRgbFrames()134   public void testShaderCallbacksTwoRgbFrames() {
135     glGenericDrawer.drawRgb(TEXTURE_ID, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_X,
136         VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
137     glGenericDrawer.drawRgb(TEXTURE_ID, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_X,
138         VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
139 
140     // Expect only one shader to be created, but two frames to be drawn.
141     verify(mockedCallbacks, times(1)).onNewShader(mockedShader);
142     verify(mockedCallbacks, times(2))
143         .onPrepareShader(
144             mockedShader, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
145   }
146 
147   @Test
testShaderCallbacksChangingShaderType()148   public void testShaderCallbacksChangingShaderType() {
149     glGenericDrawer.drawRgb(TEXTURE_ID, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_X,
150         VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
151     glGenericDrawer.drawOes(TEXTURE_ID, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_X,
152         VIEWPORT_Y, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
153 
154     // Expect two shaders to be created, and two frames to be drawn.
155     verify(mockedCallbacks, times(2)).onNewShader(mockedShader);
156     verify(mockedCallbacks, times(2))
157         .onPrepareShader(
158             mockedShader, TEX_MATRIX, FRAME_WIDTH, FRAME_HEIGHT, VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
159   }
160 }
161