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 "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                   gfx::Size size,
149                   const uint8* data) {
150  uploader->Upload(data,
151                   gfx::Rect(size),
152                   gfx::Rect(size),
153                   gfx::Vector2d(),
154                   format,
155                   size);
156}
157
158TEST(TextureUploaderTest, NumBlockingUploads) {
159  TextureUploadTestContext context;
160  scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context);
161
162  context.SetResultAvailable(0);
163  EXPECT_EQ(0u, uploader->NumBlockingUploads());
164  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
165  EXPECT_EQ(1u, uploader->NumBlockingUploads());
166  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
167  EXPECT_EQ(2u, uploader->NumBlockingUploads());
168
169  context.SetResultAvailable(1);
170  EXPECT_EQ(0u, uploader->NumBlockingUploads());
171  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
172  EXPECT_EQ(0u, uploader->NumBlockingUploads());
173  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
174  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
175  EXPECT_EQ(0u, uploader->NumBlockingUploads());
176}
177
178TEST(TextureUploaderTest, MarkPendingUploadsAsNonBlocking) {
179  TextureUploadTestContext context;
180  scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context);
181
182  context.SetResultAvailable(0);
183  EXPECT_EQ(0u, uploader->NumBlockingUploads());
184  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
185  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
186  EXPECT_EQ(2u, uploader->NumBlockingUploads());
187
188  uploader->MarkPendingUploadsAsNonBlocking();
189  EXPECT_EQ(0u, uploader->NumBlockingUploads());
190  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
191  EXPECT_EQ(1u, uploader->NumBlockingUploads());
192
193  context.SetResultAvailable(1);
194  EXPECT_EQ(0u, uploader->NumBlockingUploads());
195  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(), NULL);
196  uploader->MarkPendingUploadsAsNonBlocking();
197  EXPECT_EQ(0u, uploader->NumBlockingUploads());
198}
199
200TEST(TextureUploaderTest, UploadContentsTest) {
201  TextureUploadTestContext context;
202  scoped_ptr<TextureUploader> uploader = TextureUploader::Create(&context);
203
204  uint8 buffer[256 * 256 * 4];
205
206  // Upload a tightly packed 256x256 RGBA texture.
207  memset(buffer, 0, sizeof(buffer));
208  for (int i = 0; i < 256; ++i) {
209    // Mark the beginning and end of each row, for the test.
210    buffer[i * 4 * 256] = 0x1;
211    buffer[(i + 1) * 4 * 256 - 1] = 0x2;
212  }
213  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(256, 256), buffer);
214
215  // Upload a tightly packed 41x43 RGBA texture.
216  memset(buffer, 0, sizeof(buffer));
217  for (int i = 0; i < 43; ++i) {
218    // Mark the beginning and end of each row, for the test.
219    buffer[i * 4 * 41] = 0x1;
220    buffer[(i + 1) * 4 * 41 - 1] = 0x2;
221  }
222  UploadTexture(uploader.get(), RGBA_8888, gfx::Size(41, 43), buffer);
223
224  // Upload a tightly packed 82x86 LUMINANCE texture.
225  memset(buffer, 0, sizeof(buffer));
226  for (int i = 0; i < 86; ++i) {
227    // Mark the beginning and end of each row, for the test.
228    buffer[i * 1 * 82] = 0x1;
229    buffer[(i + 1) * 82 - 1] = 0x2;
230  }
231  UploadTexture(uploader.get(), LUMINANCE_8, gfx::Size(82, 86), buffer);
232}
233
234}  // namespace
235}  // namespace cc
236