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