• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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