1// Copyright 2012 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 "cc/scheduler/texture_uploader.h"
6
7#include "cc/base/util.h"
8#include "cc/resources/prioritized_resource.h"
9#include "cc/test/test_web_graphics_context_3d.h"
10#include "testing/gmock/include/gmock/gmock.h"
11#include "testing/gtest/include/gtest/gtest.h"
12#include "third_party/khronos/GLES2/gl2.h"
13#include "third_party/khronos/GLES2/gl2ext.h"
14
15using WebKit::WGC3Denum;
16using WebKit::WGC3Dint;
17using WebKit::WGC3Dsizei;
18using WebKit::WebGLId;
19using WebKit::WGC3Duint;
20
21namespace cc {
22namespace {
23
24class TestWebGraphicsContext3DTextureUpload : public TestWebGraphicsContext3D {
25 public:
26  TestWebGraphicsContext3DTextureUpload()
27      : result_available_(0),
28        unpack_alignment_(4) {}
29
30  virtual void pixelStorei(WGC3Denum pname, WGC3Dint param) OVERRIDE {
31    switch (pname) {
32      case GL_UNPACK_ALIGNMENT:
33        // Param should be a power of two <= 8.
34        EXPECT_EQ(0, param & (param - 1));
35        EXPECT_GE(8, param);
36        switch (param) {
37          case 1:
38          case 2:
39          case 4:
40          case 8:
41            unpack_alignment_ = param;
42            break;
43          default:
44            break;
45        }
46        break;
47      default:
48        break;
49    }
50  }
51
52  virtual void getQueryObjectuivEXT(WebGLId, WGC3Denum type, WGC3Duint* value)
53      OVERRIDE {
54    switch (type) {
55      case GL_QUERY_RESULT_AVAILABLE_EXT:
56        *value = result_available_;
57        break;
58      default:
59        *value = 0;
60        break;
61    }
62  }
63
64  virtual void texSubImage2D(WGC3Denum target,
65                             WGC3Dint level,
66                             WGC3Dint xoffset,
67                             WGC3Dint yoffset,
68                             WGC3Dsizei width,
69                             WGC3Dsizei height,
70                             WGC3Denum format,
71                             WGC3Denum type,
72                             const void* pixels) OVERRIDE {
73    EXPECT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
74    EXPECT_EQ(0, level);
75    EXPECT_LE(0, width);
76    EXPECT_LE(0, height);
77    EXPECT_LE(0, xoffset);
78    EXPECT_LE(0, yoffset);
79    EXPECT_LE(0, width);
80    EXPECT_LE(0, height);
81
82    // Check for allowed format/type combination.
83    unsigned int bytes_per_pixel = 0;
84    switch (format) {
85      case GL_ALPHA:
86        EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
87        bytes_per_pixel = 1;
88        break;
89      case GL_RGB:
90        EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_4_4_4_4), type);
91        EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_5_5_5_1), type);
92        switch (type) {
93          case GL_UNSIGNED_BYTE:
94            bytes_per_pixel = 3;
95            break;
96          case GL_UNSIGNED_SHORT_5_6_5:
97            bytes_per_pixel = 2;
98            break;
99        }
100        break;
101      case GL_RGBA:
102        EXPECT_NE(static_cast<unsigned>(GL_UNSIGNED_SHORT_5_6_5), type);
103        switch (type) {
104          case GL_UNSIGNED_BYTE:
105            bytes_per_pixel = 4;
106            break;
107          case GL_UNSIGNED_SHORT_4_4_4_4:
108            bytes_per_pixel = 2;
109            break;
110          case GL_UNSIGNED_SHORT_5_5_5_1:
111            bytes_per_pixel = 2;
112            break;
113        }
114        break;
115      case GL_LUMINANCE:
116        EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
117        bytes_per_pixel = 1;
118        break;
119      case GL_LUMINANCE_ALPHA:
120        EXPECT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
121        bytes_per_pixel = 2;
122        break;
123    }
124
125    // If NULL, we aren't checking texture contents.
126    if (pixels == NULL)
127      return;
128
129    const uint8* bytes = static_cast<const uint8*>(pixels);
130    // We'll expect the first byte of every row to be 0x1, and the last byte to
131    // be 0x2.
132    const unsigned int stride =
133        RoundUp(bytes_per_pixel * width, unpack_alignment_);
134    for (WGC3Dsizei row = 0; row < height; ++row) {
135      const uint8* row_bytes =
136          bytes + (xoffset * bytes_per_pixel + (yoffset + row) * stride);
137      EXPECT_EQ(0x1, row_bytes[0]);
138      EXPECT_EQ(0x2, row_bytes[width * bytes_per_pixel - 1]);
139    }
140  }
141
142  void SetResultAvailable(unsigned result_available) {
143    result_available_ = result_available;
144  }
145
146 private:
147  unsigned result_available_;
148  unsigned unpack_alignment_;
149
150  DISALLOW_COPY_AND_ASSIGN(TestWebGraphicsContext3DTextureUpload);
151};
152
153void UploadTexture(TextureUploader* uploader,
154                   WGC3Denum format,
155                   gfx::Size size,
156                   const uint8* data) {
157  uploader->Upload(data,
158                   gfx::Rect(size),
159                   gfx::Rect(size),
160                   gfx::Vector2d(),
161                   format,
162                   size);
163}
164
165TEST(TextureUploaderTest, NumBlockingUploads) {
166  scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context(
167      new TestWebGraphicsContext3DTextureUpload);
168  scoped_ptr<TextureUploader> uploader =
169      TextureUploader::Create(fake_context.get(), false, false);
170
171  fake_context->SetResultAvailable(0);
172  EXPECT_EQ(0u, uploader->NumBlockingUploads());
173  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
174  EXPECT_EQ(1u, uploader->NumBlockingUploads());
175  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
176  EXPECT_EQ(2u, uploader->NumBlockingUploads());
177
178  fake_context->SetResultAvailable(1);
179  EXPECT_EQ(0u, uploader->NumBlockingUploads());
180  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
181  EXPECT_EQ(0u, uploader->NumBlockingUploads());
182  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
183  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
184  EXPECT_EQ(0u, uploader->NumBlockingUploads());
185}
186
187TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) {
188  scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context(
189      new TestWebGraphicsContext3DTextureUpload);
190  scoped_ptr<TextureUploader> uploader =
191      TextureUploader::Create(fake_context.get(), false, false);
192
193  fake_context->SetResultAvailable(0);
194  EXPECT_EQ(0u, uploader->NumBlockingUploads());
195  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
196  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
197  EXPECT_EQ(2u, uploader->NumBlockingUploads());
198
199  uploader->MarkPendingUploadsAsNonBlocking();
200  EXPECT_EQ(0u, uploader->NumBlockingUploads());
201  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
202  EXPECT_EQ(1u, uploader->NumBlockingUploads());
203
204  fake_context->SetResultAvailable(1);
205  EXPECT_EQ(0u, uploader->NumBlockingUploads());
206  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(), NULL);
207  uploader->MarkPendingUploadsAsNonBlocking();
208  EXPECT_EQ(0u, uploader->NumBlockingUploads());
209}
210
211TEST(TextureUploaderTest, UploadContentsTest) {
212  scoped_ptr<TestWebGraphicsContext3DTextureUpload> fake_context(
213      new TestWebGraphicsContext3DTextureUpload);
214  scoped_ptr<TextureUploader> uploader =
215      TextureUploader::Create(fake_context.get(), false, false);
216  uint8 buffer[256 * 256 * 4];
217
218  // Upload a tightly packed 256x256 RGBA texture.
219  memset(buffer, 0, sizeof(buffer));
220  for (int i = 0; i < 256; ++i) {
221    // Mark the beginning and end of each row, for the test.
222    buffer[i * 4 * 256] = 0x1;
223    buffer[(i + 1) * 4 * 256 - 1] = 0x2;
224  }
225  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(256, 256), buffer);
226
227  // Upload a tightly packed 41x43 RGBA texture.
228  memset(buffer, 0, sizeof(buffer));
229  for (int i = 0; i < 43; ++i) {
230    // Mark the beginning and end of each row, for the test.
231    buffer[i * 4 * 41] = 0x1;
232    buffer[(i + 1) * 4 * 41 - 1] = 0x2;
233  }
234  UploadTexture(uploader.get(), GL_RGBA, gfx::Size(41, 43), buffer);
235
236  // Upload a tightly packed 82x86 LUMINANCE texture.
237  memset(buffer, 0, sizeof(buffer));
238  for (int i = 0; i < 86; ++i) {
239    // Mark the beginning and end of each row, for the test.
240    buffer[i * 1 * 82] = 0x1;
241    buffer[(i + 1) * 82 - 1] = 0x2;
242  }
243  UploadTexture(uploader.get(), GL_LUMINANCE, gfx::Size(82, 86), buffer);
244}
245
246}  // namespace
247}  // namespace cc
248