blob: 91909da2c01b46b1913375645aec18b469d13a3b [file] [log] [blame]
Zack Rusin544dd4b2009-05-01 12:41:38 -04001/**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include "shader.h"
28
29#include "vg_context.h"
30#include "shaders_cache.h"
31#include "paint.h"
32#include "mask.h"
33#include "image.h"
34
35#include "pipe/p_context.h"
36#include "pipe/p_screen.h"
37#include "pipe/p_state.h"
38#include "pipe/p_inlines.h"
39#include "util/u_memory.h"
40
41#define MAX_CONSTANTS 20
42
43struct shader {
44 struct vg_context *context;
45
46 VGboolean masking;
47 struct vg_paint *paint;
48 struct vg_image *image;
49
50 VGboolean drawing_image;
51 VGImageMode image_mode;
52
53 float constants[MAX_CONSTANTS];
54 struct pipe_constant_buffer cbuf;
55 struct pipe_shader_state fs_state;
56 void *fs;
57};
58
59struct shader * shader_create(struct vg_context *ctx)
60{
61 struct shader *shader = 0;
62
63 shader = CALLOC_STRUCT(shader);
64 shader->context = ctx;
65
66 return shader;
67}
68
69void shader_destroy(struct shader *shader)
70{
71 free(shader);
72}
73
74void shader_set_masking(struct shader *shader, VGboolean set)
75{
76 shader->masking = set;
77}
78
79VGboolean shader_is_masking(struct shader *shader)
80{
81 return shader->masking;
82}
83
84void shader_set_paint(struct shader *shader, struct vg_paint *paint)
85{
86 shader->paint = paint;
87}
88
89struct vg_paint * shader_paint(struct shader *shader)
90{
91 return shader->paint;
92}
93
94
95static void setup_constant_buffer(struct shader *shader)
96{
97 struct vg_context *ctx = shader->context;
98 struct pipe_context *pipe = shader->context->pipe;
99 struct pipe_constant_buffer *cbuf = &shader->cbuf;
100 VGint param_bytes = paint_constant_buffer_size(shader->paint);
101 float temp_buf[MAX_CONSTANTS];
102
103 assert(param_bytes <= sizeof(temp_buf));
104 paint_fill_constant_buffer(shader->paint, temp_buf);
105
106 if (cbuf->buffer == NULL ||
107 memcmp(temp_buf, shader->constants, param_bytes) != 0)
108 {
109 pipe_buffer_reference(&cbuf->buffer, NULL);
110
111 memcpy(shader->constants, temp_buf, param_bytes);
112 cbuf->buffer = pipe_user_buffer_create(pipe->screen,
113 &shader->constants,
114 sizeof(shader->constants));
115 }
116
117 ctx->pipe->set_constant_buffer(ctx->pipe, PIPE_SHADER_FRAGMENT, 0, cbuf);
118}
119
120static VGint blend_bind_samplers(struct vg_context *ctx,
121 struct pipe_sampler_state **samplers,
122 struct pipe_texture **textures)
123{
124 VGBlendMode bmode = ctx->state.vg.blend_mode;
125
126 if (bmode == VG_BLEND_MULTIPLY ||
127 bmode == VG_BLEND_SCREEN ||
128 bmode == VG_BLEND_DARKEN ||
129 bmode == VG_BLEND_LIGHTEN) {
130 struct st_framebuffer *stfb = ctx->draw_buffer;
131
132 vg_prepare_blend_surface(ctx);
133
134 samplers[2] = &ctx->blend_sampler;
135 textures[2] = stfb->blend_texture;
136
137 if (!samplers[0] || !textures[0]) {
Igor Oliveira0d051af2010-01-25 09:53:53 -0700138 samplers[0] = samplers[2];
139 textures[0] = textures[2];
Zack Rusin544dd4b2009-05-01 12:41:38 -0400140 }
141 if (!samplers[1] || !textures[1]) {
142 samplers[1] = samplers[0];
143 textures[1] = textures[0];
144 }
145
146 return 1;
147 }
148 return 0;
149}
150
151static void setup_samplers(struct shader *shader)
152{
153 struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
154 struct pipe_texture *textures[PIPE_MAX_SAMPLERS];
155 struct vg_context *ctx = shader->context;
156 /* a little wonky: we use the num as a boolean that just says
157 * whether any sampler/textures have been set. the actual numbering
158 * for samplers is always the same:
159 * 0 - paint sampler/texture for gradient/pattern
160 * 1 - mask sampler/texture
161 * 2 - blend sampler/texture
162 * 3 - image sampler/texture
163 * */
164 VGint num = 0;
165
166 samplers[0] = NULL;
167 samplers[1] = NULL;
168 samplers[2] = NULL;
169 samplers[3] = NULL;
170 textures[0] = NULL;
171 textures[1] = NULL;
172 textures[2] = NULL;
173 textures[3] = NULL;
174
175 num += paint_bind_samplers(shader->paint, samplers, textures);
176 num += mask_bind_samplers(samplers, textures);
177 num += blend_bind_samplers(ctx, samplers, textures);
178 if (shader->drawing_image && shader->image)
179 num += image_bind_samplers(shader->image, samplers, textures);
180
181 if (num) {
182 cso_set_samplers(ctx->cso_context, 4, (const struct pipe_sampler_state **)samplers);
183 cso_set_sampler_textures(ctx->cso_context, 4, textures);
184 }
185}
186
187static INLINE VGboolean is_format_bw(struct shader *shader)
188{
189#if 0
190 struct vg_context *ctx = shader->context;
191 struct st_framebuffer *stfb = ctx->draw_buffer;
192#endif
193
194 if (shader->drawing_image && shader->image) {
195 if (shader->image->format == VG_BW_1)
196 return VG_TRUE;
197 }
198
199 return VG_FALSE;
200}
201
202static void setup_shader_program(struct shader *shader)
203{
204 struct vg_context *ctx = shader->context;
205 VGint shader_id = 0;
206 VGBlendMode blend_mode = ctx->state.vg.blend_mode;
207 VGboolean black_white = is_format_bw(shader);
208
209 /* 1st stage: fill */
210 if (!shader->drawing_image ||
211 (shader->image_mode == VG_DRAW_IMAGE_MULTIPLY || shader->image_mode == VG_DRAW_IMAGE_STENCIL)) {
212 switch(paint_type(shader->paint)) {
213 case VG_PAINT_TYPE_COLOR:
214 shader_id |= VEGA_SOLID_FILL_SHADER;
215 break;
216 case VG_PAINT_TYPE_LINEAR_GRADIENT:
217 shader_id |= VEGA_LINEAR_GRADIENT_SHADER;
218 break;
219 case VG_PAINT_TYPE_RADIAL_GRADIENT:
220 shader_id |= VEGA_RADIAL_GRADIENT_SHADER;
221 break;
222 case VG_PAINT_TYPE_PATTERN:
223 shader_id |= VEGA_PATTERN_SHADER;
224 break;
225
226 default:
227 abort();
228 }
229 }
230
231 /* second stage image */
232 if (shader->drawing_image) {
233 switch(shader->image_mode) {
234 case VG_DRAW_IMAGE_NORMAL:
235 shader_id |= VEGA_IMAGE_NORMAL_SHADER;
236 break;
237 case VG_DRAW_IMAGE_MULTIPLY:
238 shader_id |= VEGA_IMAGE_MULTIPLY_SHADER;
239 break;
240 case VG_DRAW_IMAGE_STENCIL:
241 shader_id |= VEGA_IMAGE_STENCIL_SHADER;
242 break;
243 default:
244 debug_printf("Unknown image mode!");
245 }
246 }
247
248 if (shader->masking)
249 shader_id |= VEGA_MASK_SHADER;
250
251 switch(blend_mode) {
252 case VG_BLEND_MULTIPLY:
253 shader_id |= VEGA_BLEND_MULTIPLY_SHADER;
254 break;
255 case VG_BLEND_SCREEN:
256 shader_id |= VEGA_BLEND_SCREEN_SHADER;
257 break;
258 case VG_BLEND_DARKEN:
259 shader_id |= VEGA_BLEND_DARKEN_SHADER;
260 break;
261 case VG_BLEND_LIGHTEN:
262 shader_id |= VEGA_BLEND_LIGHTEN_SHADER;
263 break;
264 default:
265 /* handled by pipe_blend_state */
266 break;
267 }
268
269 if (black_white)
270 shader_id |= VEGA_BW_SHADER;
271
272 shader->fs = shaders_cache_fill(ctx->sc, shader_id);
273 cso_set_fragment_shader_handle(ctx->cso_context, shader->fs);
274}
275
276
277void shader_bind(struct shader *shader)
278{
279 /* first resolve the real paint type */
280 paint_resolve_type(shader->paint);
281
282 setup_constant_buffer(shader);
283 setup_samplers(shader);
284 setup_shader_program(shader);
285}
286
287void shader_set_image_mode(struct shader *shader, VGImageMode image_mode)
288{
289 shader->image_mode = image_mode;
290}
291
292VGImageMode shader_image_mode(struct shader *shader)
293{
294 return shader->image_mode;
295}
296
297void shader_set_drawing_image(struct shader *shader, VGboolean drawing_image)
298{
299 shader->drawing_image = drawing_image;
300}
301
302VGboolean shader_drawing_image(struct shader *shader)
303{
304 return shader->drawing_image;
305}
306
307void shader_set_image(struct shader *shader, struct vg_image *img)
308{
309 shader->image = img;
310}