blob: 3aa80df04d6cec56dca18db323f89ae3fb4a02ca [file] [log] [blame]
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +00001/*
2 * Copyright 2012 Google Inc.
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#ifndef GrClipMaskCache_DEFINED
9#define GrClipMaskCache_DEFINED
10
11#include "GrContext.h"
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000012#include "SkClipStack.h"
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +000013#include "SkTypes.h"
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000014
15class GrTexture;
16
17/**
18 * The stencil buffer stores the last clip path - providing a single entry
19 * "cache". This class provides similar functionality for AA clip paths
20 */
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000021class GrClipMaskCache : SkNoncopyable {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000022public:
23 GrClipMaskCache();
24
25 ~GrClipMaskCache() {
26
27 while (!fStack.empty()) {
28 GrClipStackFrame* temp = (GrClipStackFrame*) fStack.back();
29 temp->~GrClipStackFrame();
30 fStack.pop_back();
31 }
32 }
33
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000034 bool canReuse(int32_t clipGenID, const SkIRect& bounds) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000035
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000036 SkASSERT(clipGenID != SkClipStack::kWideOpenGenID);
37 SkASSERT(clipGenID != SkClipStack::kEmptyGenID);
38
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000039 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
40
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000041 // We could reuse the mask if bounds is a subset of last bounds. We'd have to communicate
42 // an offset to the caller.
bsalomon427cf282014-10-16 13:41:43 -070043 if (back->fLastMask &&
44 !back->fLastMask->wasDestroyed() &&
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000045 back->fLastBound == bounds &&
46 back->fLastClipGenID == clipGenID) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000047 return true;
48 }
49
50 return false;
51 }
52
53 void reset() {
54 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000055// SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000056 return;
57 }
58
59 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
60
61 back->reset();
62 }
63
64 /**
65 * After a "push" the clip state is entirely open. Currently, the
66 * entire clip stack will be re-rendered into a new clip mask.
67 * TODO: can we take advantage of the nested nature of the clips to
68 * reduce the mask creation cost?
69 */
70 void push();
71
72 void pop() {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000073 //SkASSERT(!fStack.empty());
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000074
75 if (!fStack.empty()) {
76 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
77
78 back->~GrClipStackFrame();
79 fStack.pop_back();
80 }
81 }
82
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000083 int32_t getLastClipGenID() const {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000084
85 if (fStack.empty()) {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000086 return SkClipStack::kInvalidGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000087 }
88
bsalomon@google.com4c2443e2012-12-06 20:58:57 +000089 return ((GrClipStackFrame*) fStack.back())->fLastClipGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000090 }
91
92 GrTexture* getLastMask() {
93
94 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000095 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +000096 return NULL;
97 }
98
99 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
100
bsalomon427cf282014-10-16 13:41:43 -0700101 return back->fLastMask;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000102 }
103
104 const GrTexture* getLastMask() const {
105
106 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000107 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000108 return NULL;
109 }
110
111 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
112
bsalomon427cf282014-10-16 13:41:43 -0700113 return back->fLastMask;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000114 }
115
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000116 void acquireMask(int32_t clipGenID,
bsalomonf2703d82014-10-28 14:33:06 -0700117 const GrSurfaceDesc& desc,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000118 const SkIRect& bound) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000119
120 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000121 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000122 return;
123 }
124
125 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
126
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000127 back->acquireMask(fContext, clipGenID, desc, bound);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000128 }
129
130 int getLastMaskWidth() const {
131
132 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000133 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000134 return -1;
135 }
136
137 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
138
bsalomon427cf282014-10-16 13:41:43 -0700139 if (NULL == back->fLastMask) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000140 return -1;
141 }
142
bsalomon427cf282014-10-16 13:41:43 -0700143 return back->fLastMask->width();
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000144 }
145
146 int getLastMaskHeight() const {
147
148 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000149 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000150 return -1;
151 }
152
153 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
154
bsalomon427cf282014-10-16 13:41:43 -0700155 if (NULL == back->fLastMask) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000156 return -1;
157 }
158
bsalomon427cf282014-10-16 13:41:43 -0700159 return back->fLastMask->height();
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000160 }
161
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000162 void getLastBound(SkIRect* bound) const {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000163
164 if (fStack.empty()) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000165 SkASSERT(false);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000166 bound->setEmpty();
167 return;
168 }
169
170 GrClipStackFrame* back = (GrClipStackFrame*) fStack.back();
171
172 *bound = back->fLastBound;
173 }
174
175 void setContext(GrContext* context) {
176 fContext = context;
177 }
178
179 GrContext* getContext() {
180 return fContext;
181 }
182
bsalomonc8dc1f72014-08-21 13:02:13 -0700183 // TODO: Remove this when we hold cache keys instead of refs to textures.
184 void purgeResources() {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000185 SkDeque::F2BIter iter(fStack);
186 for (GrClipStackFrame* frame = (GrClipStackFrame*) iter.next();
187 frame != NULL;
188 frame = (GrClipStackFrame*) iter.next()) {
189 frame->reset();
190 }
191 }
192
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000193private:
194 struct GrClipStackFrame {
195
196 GrClipStackFrame() {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000197 this->reset();
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000198 }
199
200 void acquireMask(GrContext* context,
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000201 int32_t clipGenID,
bsalomonf2703d82014-10-28 14:33:06 -0700202 const GrSurfaceDesc& desc,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000203 const SkIRect& bound) {
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000204
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000205 fLastClipGenID = clipGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000206
bsalomonbcf0a522014-10-08 08:40:09 -0700207 // HACK: set the last param to true to indicate that this request is at
208 // flush time and therefore we require a scratch texture with no pending IO operations.
bsalomond309e7a2015-04-30 14:18:54 -0700209 fLastMask.reset(context->textureProvider()->refScratchTexture(
210 desc, GrTextureProvider::kApprox_ScratchTexMatch, /*flushing=*/true));
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000211
212 fLastBound = bound;
213 }
214
215 void reset () {
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000216 fLastClipGenID = SkClipStack::kInvalidGenID;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000217
bsalomonf2703d82014-10-28 14:33:06 -0700218 GrSurfaceDesc desc;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000219
bsalomon427cf282014-10-16 13:41:43 -0700220 fLastMask.reset(NULL);
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000221 fLastBound.setEmpty();
222 }
223
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000224 int32_t fLastClipGenID;
225 // The mask's width & height values are used by GrClipMaskManager to correctly scale the
bsalomonc8dc1f72014-08-21 13:02:13 -0700226 // texture coords for the geometry drawn with this mask. TODO: This should be a cache key
227 // and not a hard ref to a texture.
bsalomon427cf282014-10-16 13:41:43 -0700228 SkAutoTUnref<GrTexture> fLastMask;
bsalomon@google.com4c2443e2012-12-06 20:58:57 +0000229 // fLastBound stores the bounding box of the clip mask in clip-stack space. This rect is
230 // used by GrClipMaskManager to position a rect and compute texture coords for the mask.
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000231 SkIRect fLastBound;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000232 };
233
234 GrContext* fContext;
235 SkDeque fStack;
236
commit-bot@chromium.orga0b40282013-09-18 13:00:55 +0000237 typedef SkNoncopyable INHERITED;
robertphillips@google.com1fcc1b82012-08-29 12:52:05 +0000238};
239
240#endif // GrClipMaskCache_DEFINED