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