xref: /aosp_15_r20/external/skia/tests/MultiPictureDocumentTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  *
7*c8dee2aaSAndroid Build Coastguard Worker  * This test confirms that a MultiPictureDocument can be serialized and deserialized without error.
8*c8dee2aaSAndroid Build Coastguard Worker  * And that the pictures within it are re-created accurately
9*c8dee2aaSAndroid Build Coastguard Worker  */
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDocument.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSerialProcs.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkStream.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextBlob.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "include/docs/SkMultiPictureDocument.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "tools/SkSharingProc.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
36*c8dee2aaSAndroid Build Coastguard Worker 
37*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
38*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker // Covers rects, ovals, paths, images, text
draw_basic(SkCanvas * canvas,int seed,sk_sp<SkImage> image)41*c8dee2aaSAndroid Build Coastguard Worker static void draw_basic(SkCanvas* canvas, int seed, sk_sp<SkImage> image) {
42*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawColor(SK_ColorWHITE);
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
45*c8dee2aaSAndroid Build Coastguard Worker     paint.setStyle(SkPaint::kStroke_Style);
46*c8dee2aaSAndroid Build Coastguard Worker     paint.setStrokeWidth(seed);
47*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorRED);
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect = SkRect::MakeXYWH(50+seed, 50+seed, 4*seed, 60);
50*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRect(rect, paint);
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker     SkRRect oval;
53*c8dee2aaSAndroid Build Coastguard Worker     oval.setOval(rect);
54*c8dee2aaSAndroid Build Coastguard Worker     oval.offset(40, 60+seed);
55*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorBLUE);
56*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRRect(oval, paint);
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorCYAN);
59*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawCircle(180, 50, 5*seed, paint);
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker     rect.offset(80, 0);
62*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorYELLOW);
63*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawRoundRect(rect, 10, 10, paint);
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker     SkPath path;
66*c8dee2aaSAndroid Build Coastguard Worker     path.cubicTo(768, 0, -512, 256, 256, 256);
67*c8dee2aaSAndroid Build Coastguard Worker     paint.setColor(SK_ColorGREEN);
68*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPath(path, paint);
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawImage(image, 128-seed, 128, SkSamplingOptions(), &paint);
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker     if (seed % 2 == 0) {
73*c8dee2aaSAndroid Build Coastguard Worker         SkRect rect2 = SkRect::MakeXYWH(0, 0, 40, 60);
74*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawImageRect(image, rect2, SkSamplingOptions(), &paint);
75*c8dee2aaSAndroid Build Coastguard Worker     }
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint2;
78*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = ToolUtils::DefaultFont();
79*c8dee2aaSAndroid Build Coastguard Worker     font.setSize(2 + seed);
80*c8dee2aaSAndroid Build Coastguard Worker     auto text = SkTextBlob::MakeFromString(SkStringPrintf("Frame %d", seed).c_str(), font);
81*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawTextBlob(text.get(), 50, 25, paint2);
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker // Covers all of the above and drawing nested sub-pictures.
draw_advanced(SkCanvas * canvas,int seed,sk_sp<SkImage> image,sk_sp<SkPicture> sub)85*c8dee2aaSAndroid Build Coastguard Worker static void draw_advanced(SkCanvas* canvas, int seed, sk_sp<SkImage> image, sk_sp<SkPicture> sub) {
86*c8dee2aaSAndroid Build Coastguard Worker     draw_basic(canvas, seed, image);
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     // Use subpicture twice in different places
89*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPicture(sub);
90*c8dee2aaSAndroid Build Coastguard Worker     canvas->save();
91*c8dee2aaSAndroid Build Coastguard Worker     canvas->translate(seed, seed);
92*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPicture(sub);
93*c8dee2aaSAndroid Build Coastguard Worker     canvas->restore();
94*c8dee2aaSAndroid Build Coastguard Worker }
95*c8dee2aaSAndroid Build Coastguard Worker 
96*c8dee2aaSAndroid Build Coastguard Worker // Test serialization and deserialization of multi picture document
DEF_TEST(SkMultiPictureDocument_Serialize_and_deserialize,reporter)97*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkMultiPictureDocument_Serialize_and_deserialize, reporter) {
98*c8dee2aaSAndroid Build Coastguard Worker     // Create the stream we will serialize into.
99*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker     // Create the image sharing proc.
102*c8dee2aaSAndroid Build Coastguard Worker     SkSharingSerialContext ctx;
103*c8dee2aaSAndroid Build Coastguard Worker     SkSerialProcs procs;
104*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageProc = SkSharingSerialContext::serializeImage;
105*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageCtx = &ctx;
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     // Create the multi picture document used for recording frames.
108*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkDocument> multipic = SkMultiPictureDocument::Make(&stream, &procs);
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker     static const int NUM_FRAMES = 12;
111*c8dee2aaSAndroid Build Coastguard Worker     static const int WIDTH = 256;
112*c8dee2aaSAndroid Build Coastguard Worker     static const int HEIGHT = 256;
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     // Make an image to be used in a later step.
115*c8dee2aaSAndroid Build Coastguard Worker     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
116*c8dee2aaSAndroid Build Coastguard Worker     surface->getCanvas()->clear(SK_ColorGREEN);
117*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> image(surface->makeImageSnapshot());
118*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, image);
119*c8dee2aaSAndroid Build Coastguard Worker 
120*c8dee2aaSAndroid Build Coastguard Worker     // Make a subpicture to be used in a later step
121*c8dee2aaSAndroid Build Coastguard Worker     SkPictureRecorder pr;
122*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* subCanvas = pr.beginRecording(100, 100);
123*c8dee2aaSAndroid Build Coastguard Worker     draw_basic(subCanvas, 42, image);
124*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPicture> sub = pr.finishRecordingAsPicture();
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker     const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT);
127*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<SkImage>> expectedImages;
128*c8dee2aaSAndroid Build Coastguard Worker 
129*c8dee2aaSAndroid Build Coastguard Worker     for (int i=0; i<NUM_FRAMES; i++) {
130*c8dee2aaSAndroid Build Coastguard Worker         SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT);
131*c8dee2aaSAndroid Build Coastguard Worker         draw_advanced(pictureCanvas, i, image, sub);
132*c8dee2aaSAndroid Build Coastguard Worker         multipic->endPage();
133*c8dee2aaSAndroid Build Coastguard Worker         // Also draw the picture to an image for later comparison
134*c8dee2aaSAndroid Build Coastguard Worker         auto surf = SkSurfaces::Raster(info);
135*c8dee2aaSAndroid Build Coastguard Worker         draw_advanced(surf->getCanvas(), i, image, sub);
136*c8dee2aaSAndroid Build Coastguard Worker         expectedImages.push_back(surf->makeImageSnapshot());
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker     // Finalize
139*c8dee2aaSAndroid Build Coastguard Worker     multipic->close();
140*c8dee2aaSAndroid Build Coastguard Worker 
141*c8dee2aaSAndroid Build Coastguard Worker     // Confirm written data is at least as large as the magic word
142*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream();
143*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, writtenStream->getLength() > 24,
144*c8dee2aaSAndroid Build Coastguard Worker         "Written data length too short (%zu)", writtenStream->getLength());
145*c8dee2aaSAndroid Build Coastguard Worker     // SkDebugf("Multi Frame file size = %zu\n", writtenStream->getLength());
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     // Set up deserialization
148*c8dee2aaSAndroid Build Coastguard Worker     SkSharingDeserialContext deserialContext;
149*c8dee2aaSAndroid Build Coastguard Worker     SkDeserialProcs dprocs;
150*c8dee2aaSAndroid Build Coastguard Worker     dprocs.fImageProc = SkSharingDeserialContext::deserializeImage;
151*c8dee2aaSAndroid Build Coastguard Worker     dprocs.fImageCtx = &deserialContext;
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker     // Confirm data is a MultiPictureDocument
154*c8dee2aaSAndroid Build Coastguard Worker     int frame_count = SkMultiPictureDocument::ReadPageCount(writtenStream.get());
155*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, frame_count == NUM_FRAMES,
156*c8dee2aaSAndroid Build Coastguard Worker         "Expected %d frames, got %d. \n 0 frames may indicate the written file was not a "
157*c8dee2aaSAndroid Build Coastguard Worker         "MultiPictureDocument.", NUM_FRAMES, frame_count);
158*c8dee2aaSAndroid Build Coastguard Worker 
159*c8dee2aaSAndroid Build Coastguard Worker     // Deserialize
160*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkDocumentPage> frames(frame_count);
161*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
162*c8dee2aaSAndroid Build Coastguard Worker         SkMultiPictureDocument::Read(writtenStream.get(), frames.data(), frame_count, &dprocs),
163*c8dee2aaSAndroid Build Coastguard Worker         "Failed while reading MultiPictureDocument");
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     // Examine each frame.
166*c8dee2aaSAndroid Build Coastguard Worker     int i=0;
167*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& frame : frames) {
168*c8dee2aaSAndroid Build Coastguard Worker         SkRect bounds = frame.fPicture->cullRect();
169*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, bounds.width() == WIDTH,
170*c8dee2aaSAndroid Build Coastguard Worker             "Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width());
171*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, bounds.height() == HEIGHT,
172*c8dee2aaSAndroid Build Coastguard Worker             "Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height());
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker         auto surf = SkSurfaces::Raster(info);
175*c8dee2aaSAndroid Build Coastguard Worker         surf->getCanvas()->drawPicture(frame.fPicture);
176*c8dee2aaSAndroid Build Coastguard Worker         auto img = surf->makeImageSnapshot();
177*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), expectedImages[i].get()),
178*c8dee2aaSAndroid Build Coastguard Worker                         "Frame %d is wrong", i);
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker         i++;
181*c8dee2aaSAndroid Build Coastguard Worker     }
182*c8dee2aaSAndroid Build Coastguard Worker }
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_GANESH) && defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
186*c8dee2aaSAndroid Build Coastguard Worker 
187*c8dee2aaSAndroid Build Coastguard Worker #include "include/android/AHardwareBufferUtils.h"
188*c8dee2aaSAndroid Build Coastguard Worker #include "include/android/GrAHardwareBufferUtils.h"
189*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
190*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
191*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
192*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrDirectContext.h"
193*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/SkImageGanesh.h"
194*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
195*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDirectContextPriv.h"
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker #include <android/hardware_buffer.h>
198*c8dee2aaSAndroid Build Coastguard Worker 
199*c8dee2aaSAndroid Build Coastguard Worker static const int DEV_W = 16, DEV_H = 16;
200*c8dee2aaSAndroid Build Coastguard Worker 
get_src_color(int x,int y)201*c8dee2aaSAndroid Build Coastguard Worker static SkPMColor get_src_color(int x, int y) {
202*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(x >= 0 && x < DEV_W);
203*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(y >= 0 && y < DEV_H);
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     U8CPU r = x;
206*c8dee2aaSAndroid Build Coastguard Worker     U8CPU g = y;
207*c8dee2aaSAndroid Build Coastguard Worker     U8CPU b = 0xc;
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker     U8CPU a = 0xff;
210*c8dee2aaSAndroid Build Coastguard Worker     switch ((x+y) % 5) {
211*c8dee2aaSAndroid Build Coastguard Worker         case 0:
212*c8dee2aaSAndroid Build Coastguard Worker             a = 0xff;
213*c8dee2aaSAndroid Build Coastguard Worker             break;
214*c8dee2aaSAndroid Build Coastguard Worker         case 1:
215*c8dee2aaSAndroid Build Coastguard Worker             a = 0x80;
216*c8dee2aaSAndroid Build Coastguard Worker             break;
217*c8dee2aaSAndroid Build Coastguard Worker         case 2:
218*c8dee2aaSAndroid Build Coastguard Worker             a = 0xCC;
219*c8dee2aaSAndroid Build Coastguard Worker             break;
220*c8dee2aaSAndroid Build Coastguard Worker         case 4:
221*c8dee2aaSAndroid Build Coastguard Worker             a = 0x01;
222*c8dee2aaSAndroid Build Coastguard Worker             break;
223*c8dee2aaSAndroid Build Coastguard Worker         case 3:
224*c8dee2aaSAndroid Build Coastguard Worker             a = 0x00;
225*c8dee2aaSAndroid Build Coastguard Worker             break;
226*c8dee2aaSAndroid Build Coastguard Worker     }
227*c8dee2aaSAndroid Build Coastguard Worker     a = 0xff;
228*c8dee2aaSAndroid Build Coastguard Worker     return SkPremultiplyARGBInline(a, r, g, b);
229*c8dee2aaSAndroid Build Coastguard Worker }
230*c8dee2aaSAndroid Build Coastguard Worker 
make_src_bitmap()231*c8dee2aaSAndroid Build Coastguard Worker static SkBitmap make_src_bitmap() {
232*c8dee2aaSAndroid Build Coastguard Worker     static SkBitmap bmp;
233*c8dee2aaSAndroid Build Coastguard Worker     if (bmp.isNull()) {
234*c8dee2aaSAndroid Build Coastguard Worker         bmp.allocN32Pixels(DEV_W, DEV_H);
235*c8dee2aaSAndroid Build Coastguard Worker         intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
236*c8dee2aaSAndroid Build Coastguard Worker         for (int y = 0; y < DEV_H; ++y) {
237*c8dee2aaSAndroid Build Coastguard Worker             for (int x = 0; x < DEV_W; ++x) {
238*c8dee2aaSAndroid Build Coastguard Worker                 SkPMColor* pixel = reinterpret_cast<SkPMColor*>(
239*c8dee2aaSAndroid Build Coastguard Worker                         pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
240*c8dee2aaSAndroid Build Coastguard Worker                 *pixel = get_src_color(x, y);
241*c8dee2aaSAndroid Build Coastguard Worker             }
242*c8dee2aaSAndroid Build Coastguard Worker         }
243*c8dee2aaSAndroid Build Coastguard Worker     }
244*c8dee2aaSAndroid Build Coastguard Worker     return bmp;
245*c8dee2aaSAndroid Build Coastguard Worker }
246*c8dee2aaSAndroid Build Coastguard Worker 
cleanup_resources(AHardwareBuffer * buffer)247*c8dee2aaSAndroid Build Coastguard Worker static void cleanup_resources(AHardwareBuffer* buffer) {
248*c8dee2aaSAndroid Build Coastguard Worker     if (buffer) {
249*c8dee2aaSAndroid Build Coastguard Worker         AHardwareBuffer_release(buffer);
250*c8dee2aaSAndroid Build Coastguard Worker     }
251*c8dee2aaSAndroid Build Coastguard Worker }
252*c8dee2aaSAndroid Build Coastguard Worker 
makeAHardwareBufferTestImage(skiatest::Reporter * reporter,GrDirectContext * context,AHardwareBuffer * buffer)253*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> makeAHardwareBufferTestImage(
254*c8dee2aaSAndroid Build Coastguard Worker     skiatest::Reporter* reporter, GrDirectContext* context, AHardwareBuffer* buffer) {
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker     const SkBitmap srcBitmap = make_src_bitmap();
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker     AHardwareBuffer_Desc hwbDesc;
259*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.width = DEV_W;
260*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.height = DEV_H;
261*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.layers = 1;
262*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN |
263*c8dee2aaSAndroid Build Coastguard Worker                     AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
264*c8dee2aaSAndroid Build Coastguard Worker                     AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
265*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
266*c8dee2aaSAndroid Build Coastguard Worker     // The following three are not used in the allocate
267*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.stride = 0;
268*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.rfu0= 0;
269*c8dee2aaSAndroid Build Coastguard Worker     hwbDesc.rfu1= 0;
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker     if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) {
272*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Failed to allocated hardware buffer, error: %d", error);
273*c8dee2aaSAndroid Build Coastguard Worker         cleanup_resources(buffer);
274*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
275*c8dee2aaSAndroid Build Coastguard Worker     }
276*c8dee2aaSAndroid Build Coastguard Worker 
277*c8dee2aaSAndroid Build Coastguard Worker     // Get actual desc for allocated buffer so we know the stride for uploading cpu data.
278*c8dee2aaSAndroid Build Coastguard Worker     AHardwareBuffer_describe(buffer, &hwbDesc);
279*c8dee2aaSAndroid Build Coastguard Worker 
280*c8dee2aaSAndroid Build Coastguard Worker     void* bufferAddr;
281*c8dee2aaSAndroid Build Coastguard Worker     if (AHardwareBuffer_lock(buffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, nullptr,
282*c8dee2aaSAndroid Build Coastguard Worker                              &bufferAddr)) {
283*c8dee2aaSAndroid Build Coastguard Worker         ERRORF(reporter, "Failed to lock hardware buffer");
284*c8dee2aaSAndroid Build Coastguard Worker         cleanup_resources(buffer);
285*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
286*c8dee2aaSAndroid Build Coastguard Worker     }
287*c8dee2aaSAndroid Build Coastguard Worker 
288*c8dee2aaSAndroid Build Coastguard Worker     // fill buffer
289*c8dee2aaSAndroid Build Coastguard Worker     int bbp = srcBitmap.bytesPerPixel();
290*c8dee2aaSAndroid Build Coastguard Worker     uint32_t* src = (uint32_t*)srcBitmap.getPixels();
291*c8dee2aaSAndroid Build Coastguard Worker     int nextLineStep = DEV_W;
292*c8dee2aaSAndroid Build Coastguard Worker     uint32_t* dst = static_cast<uint32_t*>(bufferAddr);
293*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < DEV_H; ++y) {
294*c8dee2aaSAndroid Build Coastguard Worker         memcpy(dst, src, DEV_W * bbp);
295*c8dee2aaSAndroid Build Coastguard Worker         src += nextLineStep;
296*c8dee2aaSAndroid Build Coastguard Worker         dst += hwbDesc.stride;
297*c8dee2aaSAndroid Build Coastguard Worker     }
298*c8dee2aaSAndroid Build Coastguard Worker     AHardwareBuffer_unlock(buffer, nullptr);
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker     // Make SkImage from buffer in a way that mimics libs/hwui/AutoBackendTextureRelease
301*c8dee2aaSAndroid Build Coastguard Worker     GrBackendFormat backendFormat =
302*c8dee2aaSAndroid Build Coastguard Worker             GrAHardwareBufferUtils::GetBackendFormat(context, buffer, hwbDesc.format, false);
303*c8dee2aaSAndroid Build Coastguard Worker     GrAHardwareBufferUtils::DeleteImageProc deleteProc;
304*c8dee2aaSAndroid Build Coastguard Worker     GrAHardwareBufferUtils::UpdateImageProc updateProc;
305*c8dee2aaSAndroid Build Coastguard Worker     GrAHardwareBufferUtils::TexImageCtx imageCtx;
306*c8dee2aaSAndroid Build Coastguard Worker     GrBackendTexture texture = GrAHardwareBufferUtils::MakeBackendTexture(
307*c8dee2aaSAndroid Build Coastguard Worker         context, buffer, hwbDesc.width, hwbDesc.height,
308*c8dee2aaSAndroid Build Coastguard Worker         &deleteProc, // set by MakeBackendTexture
309*c8dee2aaSAndroid Build Coastguard Worker         &updateProc, // set by MakeBackendTexture
310*c8dee2aaSAndroid Build Coastguard Worker         &imageCtx, // set by MakeBackendTexture
311*c8dee2aaSAndroid Build Coastguard Worker         false,   // don't make protected image
312*c8dee2aaSAndroid Build Coastguard Worker         backendFormat,
313*c8dee2aaSAndroid Build Coastguard Worker         false   // isRenderable
314*c8dee2aaSAndroid Build Coastguard Worker     );
315*c8dee2aaSAndroid Build Coastguard Worker     SkColorType colorType = AHardwareBufferUtils::GetSkColorTypeFromBufferFormat(hwbDesc.format);
316*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> image = SkImages::BorrowTextureFrom(context,
317*c8dee2aaSAndroid Build Coastguard Worker                                                        texture,
318*c8dee2aaSAndroid Build Coastguard Worker                                                        kTopLeft_GrSurfaceOrigin,
319*c8dee2aaSAndroid Build Coastguard Worker                                                        colorType,
320*c8dee2aaSAndroid Build Coastguard Worker                                                        kPremul_SkAlphaType,
321*c8dee2aaSAndroid Build Coastguard Worker                                                        SkColorSpace::MakeSRGB(),
322*c8dee2aaSAndroid Build Coastguard Worker                                                        deleteProc,
323*c8dee2aaSAndroid Build Coastguard Worker                                                        imageCtx);
324*c8dee2aaSAndroid Build Coastguard Worker 
325*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, image);
326*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, image->isTextureBacked());
327*c8dee2aaSAndroid Build Coastguard Worker     return image;
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker 
330*c8dee2aaSAndroid Build Coastguard Worker // Test the onEndPage callback's intended use by processing an mskp containing AHardwareBuffer-backed SkImages
331*c8dee2aaSAndroid Build Coastguard Worker // Expected behavior is that the callback is called while the AHardwareBuffer is still valid and the
332*c8dee2aaSAndroid Build Coastguard Worker // images are copied so .close() can still access them.
333*c8dee2aaSAndroid Build Coastguard Worker // Confirm deserialized file contains images with correct data.
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkMultiPictureDocument_AHardwarebuffer,reporter,ctx_info,CtsEnforcement::kApiLevel_T)334*c8dee2aaSAndroid Build Coastguard Worker DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkMultiPictureDocument_AHardwarebuffer,
335*c8dee2aaSAndroid Build Coastguard Worker                                        reporter,
336*c8dee2aaSAndroid Build Coastguard Worker                                        ctx_info,
337*c8dee2aaSAndroid Build Coastguard Worker                                        CtsEnforcement::kApiLevel_T) {
338*c8dee2aaSAndroid Build Coastguard Worker     auto context = ctx_info.directContext();
339*c8dee2aaSAndroid Build Coastguard Worker     if (!context->priv().caps()->supportsAHardwareBufferImages()) {
340*c8dee2aaSAndroid Build Coastguard Worker         return;
341*c8dee2aaSAndroid Build Coastguard Worker     }
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker     // Create the stream we will serialize into.
344*c8dee2aaSAndroid Build Coastguard Worker     SkDynamicMemoryWStream stream;
345*c8dee2aaSAndroid Build Coastguard Worker 
346*c8dee2aaSAndroid Build Coastguard Worker     // Create the image sharing proc.
347*c8dee2aaSAndroid Build Coastguard Worker     SkSharingSerialContext ctx;
348*c8dee2aaSAndroid Build Coastguard Worker     SkSerialProcs procs;
349*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageProc = SkSharingSerialContext::serializeImage;
350*c8dee2aaSAndroid Build Coastguard Worker     procs.fImageCtx = &ctx;
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker     // Create the multi picture document used for recording frames.
353*c8dee2aaSAndroid Build Coastguard Worker     // Pass a lambda as the onEndPage callback that captures our sharing context
354*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkDocument> multipic = SkMultiPictureDocument::Make(&stream, &procs,
355*c8dee2aaSAndroid Build Coastguard Worker         [sharingCtx = &ctx](const SkPicture* pic) {
356*c8dee2aaSAndroid Build Coastguard Worker             SkSharingSerialContext::collectNonTextureImagesFromPicture(pic, sharingCtx);
357*c8dee2aaSAndroid Build Coastguard Worker         });
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker     static const int WIDTH = 256;
360*c8dee2aaSAndroid Build Coastguard Worker     static const int HEIGHT = 256;
361*c8dee2aaSAndroid Build Coastguard Worker 
362*c8dee2aaSAndroid Build Coastguard Worker     // Make an image to be used in a later step.
363*c8dee2aaSAndroid Build Coastguard Worker     AHardwareBuffer* ahbuffer = nullptr;
364*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkImage> image = makeAHardwareBufferTestImage(reporter, context, ahbuffer);
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker     const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH, HEIGHT);
367*c8dee2aaSAndroid Build Coastguard Worker     std::vector<sk_sp<SkImage>> expectedImages;
368*c8dee2aaSAndroid Build Coastguard Worker 
369*c8dee2aaSAndroid Build Coastguard Worker     // Record single frame
370*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* pictureCanvas = multipic->beginPage(WIDTH, HEIGHT);
371*c8dee2aaSAndroid Build Coastguard Worker     draw_basic(pictureCanvas, 0, image);
372*c8dee2aaSAndroid Build Coastguard Worker     multipic->endPage();
373*c8dee2aaSAndroid Build Coastguard Worker     // Also draw the picture to an image for later comparison
374*c8dee2aaSAndroid Build Coastguard Worker     auto surf = SkSurfaces::Raster(info);
375*c8dee2aaSAndroid Build Coastguard Worker     draw_basic(surf->getCanvas(), 0, image);
376*c8dee2aaSAndroid Build Coastguard Worker     expectedImages.push_back(surf->makeImageSnapshot());
377*c8dee2aaSAndroid Build Coastguard Worker 
378*c8dee2aaSAndroid Build Coastguard Worker     // Release Ahardwarebuffer. If the code under test has not copied it already,
379*c8dee2aaSAndroid Build Coastguard Worker     // close() will fail.
380*c8dee2aaSAndroid Build Coastguard Worker     // Note that this only works because we're doing one frame only. If this test were recording
381*c8dee2aaSAndroid Build Coastguard Worker     // two or more frames, it would have change the buffer contents instead.
382*c8dee2aaSAndroid Build Coastguard Worker     cleanup_resources(ahbuffer);
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker     // Finalize
385*c8dee2aaSAndroid Build Coastguard Worker     multipic->close();
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker     // Confirm written data is at least as large as the magic word
388*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<SkStreamAsset> writtenStream = stream.detachAsStream();
389*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, writtenStream->getLength() > 24,
390*c8dee2aaSAndroid Build Coastguard Worker         "Written data length too short (%zu)", writtenStream->getLength());
391*c8dee2aaSAndroid Build Coastguard Worker 
392*c8dee2aaSAndroid Build Coastguard Worker     // Set up deserialization
393*c8dee2aaSAndroid Build Coastguard Worker     SkSharingDeserialContext deserialContext;
394*c8dee2aaSAndroid Build Coastguard Worker     SkDeserialProcs dprocs;
395*c8dee2aaSAndroid Build Coastguard Worker     dprocs.fImageProc = SkSharingDeserialContext::deserializeImage;
396*c8dee2aaSAndroid Build Coastguard Worker     dprocs.fImageCtx = &deserialContext;
397*c8dee2aaSAndroid Build Coastguard Worker 
398*c8dee2aaSAndroid Build Coastguard Worker     // Confirm data is a MultiPictureDocument
399*c8dee2aaSAndroid Build Coastguard Worker     int frame_count = SkMultiPictureDocument::ReadPageCount(writtenStream.get());
400*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, frame_count == 1,
401*c8dee2aaSAndroid Build Coastguard Worker         "Expected 1 frame, got %d. \n 0 frames may indicate the written file was not a "
402*c8dee2aaSAndroid Build Coastguard Worker         "MultiPictureDocument.", frame_count);
403*c8dee2aaSAndroid Build Coastguard Worker 
404*c8dee2aaSAndroid Build Coastguard Worker     // Deserialize
405*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SkDocumentPage> frames(frame_count);
406*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter,
407*c8dee2aaSAndroid Build Coastguard Worker         SkMultiPictureDocument::Read(writtenStream.get(), frames.data(), frame_count, &dprocs),
408*c8dee2aaSAndroid Build Coastguard Worker         "Failed while reading MultiPictureDocument");
409*c8dee2aaSAndroid Build Coastguard Worker 
410*c8dee2aaSAndroid Build Coastguard Worker     // Examine frame.
411*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds = frames[0].fPicture->cullRect();
412*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds.width() == WIDTH,
413*c8dee2aaSAndroid Build Coastguard Worker         "Page width: expected (%d) got (%d)", WIDTH, (int)bounds.width());
414*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, bounds.height() == HEIGHT,
415*c8dee2aaSAndroid Build Coastguard Worker         "Page height: expected (%d) got (%d)", HEIGHT, (int)bounds.height());
416*c8dee2aaSAndroid Build Coastguard Worker 
417*c8dee2aaSAndroid Build Coastguard Worker     auto surf2 = SkSurfaces::Raster(info);
418*c8dee2aaSAndroid Build Coastguard Worker     surf2->getCanvas()->drawPicture(frames[0].fPicture);
419*c8dee2aaSAndroid Build Coastguard Worker     auto img = surf2->makeImageSnapshot();
420*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img.get(), expectedImages[0].get()));
421*c8dee2aaSAndroid Build Coastguard Worker }
422*c8dee2aaSAndroid Build Coastguard Worker 
423*c8dee2aaSAndroid Build Coastguard Worker #endif // android compilation
424