1 /*
2 * Copyright 2022 Google LLC
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 #include "src/gpu/AtlasTypes.h"
9
10 #include "include/private/base/SkMalloc.h"
11 #include "src/core/SkOpts.h"
12
13 namespace skgpu {
14
Plot(int pageIndex,int plotIndex,AtlasGenerationCounter * generationCounter,int offX,int offY,int width,int height,SkColorType colorType,size_t bpp)15 Plot::Plot(int pageIndex, int plotIndex, AtlasGenerationCounter* generationCounter,
16 int offX, int offY, int width, int height, SkColorType colorType, size_t bpp)
17 : fLastUpload(AtlasToken::InvalidToken())
18 , fLastUse(AtlasToken::InvalidToken())
19 , fFlushesSinceLastUse(0)
20 , fPageIndex(pageIndex)
21 , fPlotIndex(plotIndex)
22 , fGenerationCounter(generationCounter)
23 , fGenID(fGenerationCounter->next())
24 , fPlotLocator(fPageIndex, fPlotIndex, fGenID)
25 , fData(nullptr)
26 , fWidth(width)
27 , fHeight(height)
28 , fX(offX)
29 , fY(offY)
30 , fRectanizer(width, height)
31 , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight))
32 , fColorType(colorType)
33 , fBytesPerPixel(bpp)
34 #ifdef SK_DEBUG
35 , fDirty(false)
36 #endif
37 {
38 // We expect the allocated dimensions to be a multiple of 4 bytes
39 SkASSERT(((width*fBytesPerPixel) & 0x3) == 0);
40 // The padding for faster uploads only works for 1, 2 and 4 byte texels
41 SkASSERT(fBytesPerPixel != 3 && fBytesPerPixel <= 4);
42 fDirtyRect.setEmpty();
43 fCachedRect.setEmpty();
44 }
45
~Plot()46 Plot::~Plot() {
47 sk_free(fData);
48 }
49
addSubImage(int width,int height,const void * image,AtlasLocator * atlasLocator)50 bool Plot::addSubImage(int width, int height, const void* image, AtlasLocator* atlasLocator) {
51 SkASSERT(width <= fWidth && height <= fHeight);
52
53 SkIPoint16 loc;
54 if (!fRectanizer.addRect(width, height, &loc)) {
55 return false;
56 }
57
58 auto rect = skgpu::IRect16::MakeXYWH(loc.fX, loc.fY, width, height);
59
60 if (!fData) {
61 fData = reinterpret_cast<unsigned char*>(
62 sk_calloc_throw(fBytesPerPixel * fWidth * fHeight));
63 }
64 size_t rowBytes = width * fBytesPerPixel;
65 const unsigned char* imagePtr = (const unsigned char*)image;
66 // point ourselves at the right starting spot
67 unsigned char* dataPtr = fData;
68 dataPtr += fBytesPerPixel * fWidth * rect.fTop;
69 dataPtr += fBytesPerPixel * rect.fLeft;
70 // copy into the data buffer, swizzling as we go if this is ARGB data
71 constexpr bool kBGRAIsNative = kN32_SkColorType == kBGRA_8888_SkColorType;
72 if (4 == fBytesPerPixel && kBGRAIsNative) {
73 for (int i = 0; i < height; ++i) {
74 SkOpts::RGBA_to_BGRA((uint32_t*)dataPtr, (const uint32_t*)imagePtr, width);
75 dataPtr += fBytesPerPixel * fWidth;
76 imagePtr += rowBytes;
77 }
78 } else {
79 for (int i = 0; i < height; ++i) {
80 memcpy(dataPtr, imagePtr, rowBytes);
81 dataPtr += fBytesPerPixel * fWidth;
82 imagePtr += rowBytes;
83 }
84 }
85
86 fDirtyRect.join({rect.fLeft, rect.fTop, rect.fRight, rect.fBottom});
87
88 rect.offset(fOffset.fX, fOffset.fY);
89 atlasLocator->updateRect(rect);
90 SkDEBUGCODE(fDirty = true;)
91
92 return true;
93 }
94
prepareForUpload(bool useCachedUploads)95 std::pair<const void*, SkIRect> Plot::prepareForUpload(bool useCachedUploads) {
96 // We should only be issuing uploads if we are dirty or uploading the cached rect
97 SkASSERT(fDirty || useCachedUploads);
98 if (!fData) {
99 return {nullptr, {}};
100 }
101 size_t rowBytes = fBytesPerPixel * fWidth;
102 const unsigned char* dataPtr;
103 SkIRect offsetRect;
104 if (!fDirtyRect.isEmpty()) {
105 // Clamp to 4-byte aligned boundaries
106 unsigned int clearBits = 0x3 / fBytesPerPixel;
107 fDirtyRect.fLeft &= ~clearBits;
108 fDirtyRect.fRight += clearBits;
109 fDirtyRect.fRight &= ~clearBits;
110 SkASSERT(fDirtyRect.fRight <= fWidth);
111 if (!useCachedUploads) {
112 // Set up dataPtr
113 dataPtr = fData;
114 dataPtr += rowBytes * fDirtyRect.fTop;
115 dataPtr += fBytesPerPixel * fDirtyRect.fLeft;
116 offsetRect = fDirtyRect.makeOffset(fOffset.fX, fOffset.fY);
117 }
118 fCachedRect.join(fDirtyRect);
119 fDirtyRect.setEmpty();
120 SkDEBUGCODE(fDirty = false);
121 }
122
123 if (useCachedUploads) {
124 // use the entire cached rect rather than just the dirty rect
125 dataPtr = fData;
126 dataPtr += rowBytes * fCachedRect.fTop;
127 dataPtr += fBytesPerPixel * fCachedRect.fLeft;
128 offsetRect = fCachedRect.makeOffset(fOffset.fX, fOffset.fY);
129 }
130
131 return { dataPtr, offsetRect };
132 }
133
resetRects()134 void Plot::resetRects() {
135 fRectanizer.reset();
136 fGenID = fGenerationCounter->next();
137 fPlotLocator = PlotLocator(fPageIndex, fPlotIndex, fGenID);
138 fLastUpload = AtlasToken::InvalidToken();
139 fLastUse = AtlasToken::InvalidToken();
140
141 // zero out the plot
142 if (fData) {
143 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight);
144 }
145
146 fDirtyRect.setEmpty();
147 fCachedRect.setEmpty();
148 SkDEBUGCODE(fDirty = false;)
149 }
150
151 } // namespace skgpu
152