1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 // This is a GPU-backend specific test. It relies on static intializers to work
9 
10 #include "SkTypes.h"
11 
12 #include "GrContextFactory.h"
13 #include "GrContextPriv.h"
14 #include "GrGpu.h"
15 #include "GrResourceProvider.h"
16 #include "GrSurfaceProxy.h"
17 #include "GrTexture.h"
18 #include "SkGr.h"
19 #include "SkSurface.h"
20 #include "Test.h"
21 
22 using sk_gpu_test::GrContextFactory;
23 
fill_transfer_data(int left,int top,int width,int height,int bufferWidth,GrColor * data)24 void fill_transfer_data(int left, int top, int width, int height, int bufferWidth,
25                         GrColor* data) {
26 
27     // build red-green gradient
28     for (int j = top; j < top + height; ++j) {
29         for (int i = left; i < left + width; ++i) {
30             unsigned int red = (unsigned int)(256.f*((i - left) / (float)width));
31             unsigned int green = (unsigned int)(256.f*((j - top) / (float)height));
32             data[i + j*bufferWidth] = GrColorPackRGBA(red - (red>>8),
33                                                       green - (green>>8), 0xff, 0xff);
34         }
35     }
36 }
37 
does_full_buffer_contain_correct_values(GrColor * srcBuffer,GrColor * dstBuffer,int width,int height,int bufferWidth,int bufferHeight)38 bool does_full_buffer_contain_correct_values(GrColor* srcBuffer,
39                                              GrColor* dstBuffer,
40                                              int width,
41                                              int height,
42                                              int bufferWidth,
43                                              int bufferHeight) {
44     GrColor* srcPtr = srcBuffer;
45     GrColor* dstPtr = dstBuffer;
46 
47     for (int j = 0; j < height; ++j) {
48         for (int i = 0; i < width; ++i) {
49             if (srcPtr[i] != dstPtr[i]) {
50                 return false;
51             }
52         }
53         srcPtr += bufferWidth;
54         dstPtr += bufferWidth;
55     }
56     return true;
57 }
58 
basic_transfer_test(skiatest::Reporter * reporter,GrContext * context,GrColorType colorType,bool renderTarget)59 void basic_transfer_test(skiatest::Reporter* reporter, GrContext* context, GrColorType colorType,
60                          bool renderTarget) {
61     if (GrCaps::kNone_MapFlags == context->contextPriv().caps()->mapBufferFlags()) {
62         return;
63     }
64 
65     auto resourceProvider = context->contextPriv().resourceProvider();
66     GrGpu* gpu = context->contextPriv().getGpu();
67 
68     // set up the data
69     const int kTextureWidth = 16;
70     const int kTextureHeight = 16;
71 #ifdef SK_BUILD_FOR_IOS
72     // UNPACK_ROW_LENGTH is broken on iOS so rowBytes needs to match data width
73     const int kBufferWidth = GrBackendApi::kOpenGL == context->backend() ? 16 : 20;
74 #else
75     const int kBufferWidth = 20;
76 #endif
77     const int kBufferHeight = 16;
78     size_t rowBytes = kBufferWidth * sizeof(GrColor);
79     SkAutoTMalloc<GrColor> srcBuffer(kBufferWidth*kBufferHeight);
80     SkAutoTMalloc<GrColor> dstBuffer(kBufferWidth*kBufferHeight);
81 
82     fill_transfer_data(0, 0, kTextureWidth, kTextureHeight, kBufferWidth, srcBuffer.get());
83 
84     // create and fill transfer buffer
85     size_t size = rowBytes*kBufferHeight;
86     auto bufferFlags = GrResourceProvider::Flags::kNoPendingIO;
87     sk_sp<GrBuffer> buffer(resourceProvider->createBuffer(size,
88                                                           kXferCpuToGpu_GrBufferType,
89                                                           kDynamic_GrAccessPattern,
90                                                           bufferFlags));
91     if (!buffer) {
92         return;
93     }
94 
95     void* data = buffer->map();
96     memcpy(data, srcBuffer.get(), size);
97     buffer->unmap();
98 
99     for (auto srgbEncoding : {GrSRGBEncoded::kNo, GrSRGBEncoded::kYes}) {
100         // create texture
101         GrSurfaceDesc desc;
102         desc.fFlags = renderTarget ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
103         desc.fWidth = kTextureWidth;
104         desc.fHeight = kTextureHeight;
105         desc.fConfig = GrColorTypeToPixelConfig(colorType, srgbEncoding);
106         desc.fSampleCnt = 1;
107 
108         if (kUnknown_GrPixelConfig == desc.fConfig) {
109             SkASSERT(GrSRGBEncoded::kYes == srgbEncoding);
110             continue;
111         }
112 
113         if (!context->contextPriv().caps()->isConfigTexturable(desc.fConfig) ||
114             (renderTarget && !context->contextPriv().caps()->isConfigRenderable(desc.fConfig))) {
115             continue;
116         }
117 
118         sk_sp<GrTexture> tex = resourceProvider->createTexture(desc, SkBudgeted::kNo);
119         if (!tex) {
120             continue;
121         }
122 
123         //////////////////////////
124         // transfer full data
125 
126         bool result;
127         result = gpu->transferPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
128                                      buffer.get(), 0, rowBytes);
129         REPORTER_ASSERT(reporter, result);
130 
131         memset(dstBuffer.get(), 0xCDCD, size);
132         result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
133                                  dstBuffer.get(), rowBytes);
134         if (result) {
135             REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
136                                                                               dstBuffer,
137                                                                               kTextureWidth,
138                                                                               kTextureHeight,
139                                                                               kBufferWidth,
140                                                                               kBufferHeight));
141         }
142 
143         //////////////////////////
144         // transfer partial data
145 #ifdef SK_BUILD_FOR_IOS
146         // UNPACK_ROW_LENGTH is broken on iOS so we can't do partial transfers
147         if (GrBackendApi::kOpenGL == context->backend()) {
148             continue;
149         }
150 #endif
151         const int kLeft = 2;
152         const int kTop = 10;
153         const int kWidth = 10;
154         const int kHeight = 2;
155 
156         // change color of subrectangle
157         fill_transfer_data(kLeft, kTop, kWidth, kHeight, kBufferWidth, srcBuffer.get());
158         data = buffer->map();
159         memcpy(data, srcBuffer.get(), size);
160         buffer->unmap();
161 
162         size_t offset = sizeof(GrColor) * (kTop * kBufferWidth + kLeft);
163         result = gpu->transferPixels(tex.get(), kLeft, kTop, kWidth, kHeight, colorType,
164                                      buffer.get(), offset, rowBytes);
165         REPORTER_ASSERT(reporter, result);
166 
167         memset(dstBuffer.get(), 0xCDCD, size);
168         result = gpu->readPixels(tex.get(), 0, 0, kTextureWidth, kTextureHeight, colorType,
169                                  dstBuffer.get(), rowBytes);
170         if (result) {
171             REPORTER_ASSERT(reporter, does_full_buffer_contain_correct_values(srcBuffer,
172                                                                               dstBuffer,
173                                                                               kTextureWidth,
174                                                                               kTextureHeight,
175                                                                               kBufferWidth,
176                                                                               kBufferHeight));
177         }
178     }
179 }
180 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsTest,reporter,ctxInfo)181 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(TransferPixelsTest, reporter, ctxInfo) {
182     // RGBA
183     basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, false);
184     basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kRGBA_8888, true);
185 
186     // BGRA
187     basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, false);
188     basic_transfer_test(reporter, ctxInfo.grContext(), GrColorType::kBGRA_8888, true);
189 }
190