1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "main/glheader.h"
27 #include "main/context.h"
28
29 #include "main/macros.h"
30
31 #include "s_context.h"
32 #include "s_logic.h"
33 #include "s_span.h"
34
35
36 /**
37 * We do all logic ops on 4-byte GLuints.
38 * Depending on bytes per pixel, the mask array elements correspond to
39 * 1, 2 or 4 GLuints.
40 */
41 #define LOGIC_OP_LOOP(MODE, MASKSTRIDE) \
42 do { \
43 GLuint i; \
44 switch (MODE) { \
45 case GL_CLEAR: \
46 for (i = 0; i < n; i++) { \
47 if (mask[i / MASKSTRIDE]) { \
48 src[i] = 0; \
49 } \
50 } \
51 break; \
52 case GL_SET: \
53 for (i = 0; i < n; i++) { \
54 if (mask[i / MASKSTRIDE]) { \
55 src[i] = ~0; \
56 } \
57 } \
58 break; \
59 case GL_COPY: \
60 /* do nothing */ \
61 break; \
62 case GL_COPY_INVERTED: \
63 for (i = 0; i < n; i++) { \
64 if (mask[i / MASKSTRIDE]) { \
65 src[i] = ~src[i]; \
66 } \
67 } \
68 break; \
69 case GL_NOOP: \
70 for (i = 0; i < n; i++) { \
71 if (mask[i / MASKSTRIDE]) { \
72 src[i] = dest[i]; \
73 } \
74 } \
75 break; \
76 case GL_INVERT: \
77 for (i = 0; i < n; i++) { \
78 if (mask[i / MASKSTRIDE]) { \
79 src[i] = ~dest[i]; \
80 } \
81 } \
82 break; \
83 case GL_AND: \
84 for (i = 0; i < n; i++) { \
85 if (mask[i / MASKSTRIDE]) { \
86 src[i] &= dest[i]; \
87 } \
88 } \
89 break; \
90 case GL_NAND: \
91 for (i = 0; i < n; i++) { \
92 if (mask[i / MASKSTRIDE]) { \
93 src[i] = ~(src[i] & dest[i]); \
94 } \
95 } \
96 break; \
97 case GL_OR: \
98 for (i = 0; i < n; i++) { \
99 if (mask[i / MASKSTRIDE]) { \
100 src[i] |= dest[i]; \
101 } \
102 } \
103 break; \
104 case GL_NOR: \
105 for (i = 0; i < n; i++) { \
106 if (mask[i / MASKSTRIDE]) { \
107 src[i] = ~(src[i] | dest[i]); \
108 } \
109 } \
110 break; \
111 case GL_XOR: \
112 for (i = 0; i < n; i++) { \
113 if (mask[i / MASKSTRIDE]) { \
114 src[i] ^= dest[i]; \
115 } \
116 } \
117 break; \
118 case GL_EQUIV: \
119 for (i = 0; i < n; i++) { \
120 if (mask[i / MASKSTRIDE]) { \
121 src[i] = ~(src[i] ^ dest[i]); \
122 } \
123 } \
124 break; \
125 case GL_AND_REVERSE: \
126 for (i = 0; i < n; i++) { \
127 if (mask[i / MASKSTRIDE]) { \
128 src[i] = src[i] & ~dest[i]; \
129 } \
130 } \
131 break; \
132 case GL_AND_INVERTED: \
133 for (i = 0; i < n; i++) { \
134 if (mask[i / MASKSTRIDE]) { \
135 src[i] = ~src[i] & dest[i]; \
136 } \
137 } \
138 break; \
139 case GL_OR_REVERSE: \
140 for (i = 0; i < n; i++) { \
141 if (mask[i / MASKSTRIDE]) { \
142 src[i] = src[i] | ~dest[i]; \
143 } \
144 } \
145 break; \
146 case GL_OR_INVERTED: \
147 for (i = 0; i < n; i++) { \
148 if (mask[i / MASKSTRIDE]) { \
149 src[i] = ~src[i] | dest[i]; \
150 } \
151 } \
152 break; \
153 default: \
154 _mesa_problem(ctx, "bad logicop mode");\
155 } \
156 } while (0)
157
158
159
160 static inline void
logicop_uint1(struct gl_context * ctx,GLuint n,GLuint src[],const GLuint dest[],const GLubyte mask[])161 logicop_uint1(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
162 const GLubyte mask[])
163 {
164 LOGIC_OP_LOOP(ctx->Color.LogicOp, 1);
165 }
166
167
168 static inline void
logicop_uint2(struct gl_context * ctx,GLuint n,GLuint src[],const GLuint dest[],const GLubyte mask[])169 logicop_uint2(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
170 const GLubyte mask[])
171 {
172 LOGIC_OP_LOOP(ctx->Color.LogicOp, 2);
173 }
174
175
176 static inline void
logicop_uint4(struct gl_context * ctx,GLuint n,GLuint src[],const GLuint dest[],const GLubyte mask[])177 logicop_uint4(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
178 const GLubyte mask[])
179 {
180 LOGIC_OP_LOOP(ctx->Color.LogicOp, 4);
181 }
182
183
184
185 /**
186 * Apply the current logic operator to a span of RGBA pixels.
187 * We can handle horizontal runs of pixels (spans) or arrays of x/y
188 * pixel coordinates.
189 */
190 void
_swrast_logicop_rgba_span(struct gl_context * ctx,struct gl_renderbuffer * rb,SWspan * span)191 _swrast_logicop_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
192 SWspan *span)
193 {
194 void *rbPixels;
195
196 assert(span->end < SWRAST_MAX_WIDTH);
197 assert(span->arrayMask & SPAN_RGBA);
198
199 rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
200
201 if (span->array->ChanType == GL_UNSIGNED_BYTE) {
202 /* treat 4*GLubyte as GLuint */
203 logicop_uint1(ctx, span->end,
204 (GLuint *) span->array->rgba8,
205 (const GLuint *) rbPixels, span->array->mask);
206 }
207 else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
208 /* treat 2*GLushort as GLuint */
209 logicop_uint2(ctx, 2 * span->end,
210 (GLuint *) span->array->rgba16,
211 (const GLuint *) rbPixels, span->array->mask);
212 }
213 else {
214 logicop_uint4(ctx, 4 * span->end,
215 (GLuint *) span->array->attribs[VARYING_SLOT_COL0],
216 (const GLuint *) rbPixels, span->array->mask);
217 }
218 }
219