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