1 /**************************************************************************
2  *
3  * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4  * 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
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "sp_context.h"
29 #include "sp_state.h"
30 #include "sp_fs.h"
31 #include "sp_texture.h"
32 
33 #include "pipe/p_defines.h"
34 #include "util/u_memory.h"
35 #include "util/u_inlines.h"
36 #include "util/u_pstipple.h"
37 #include "draw/draw_context.h"
38 #include "draw/draw_vs.h"
39 #include "draw/draw_gs.h"
40 #include "tgsi/tgsi_dump.h"
41 #include "tgsi/tgsi_scan.h"
42 #include "tgsi/tgsi_parse.h"
43 
44 
45 /**
46  * Create a new fragment shader variant.
47  */
48 static struct sp_fragment_shader_variant *
create_fs_variant(struct softpipe_context * softpipe,struct sp_fragment_shader * fs,const struct sp_fragment_shader_variant_key * key)49 create_fs_variant(struct softpipe_context *softpipe,
50                   struct sp_fragment_shader *fs,
51                   const struct sp_fragment_shader_variant_key *key)
52 {
53    struct sp_fragment_shader_variant *var;
54    struct pipe_shader_state *stipple_fs = NULL, *curfs = &fs->shader;
55    unsigned unit = 0;
56 
57 #if DO_PSTIPPLE_IN_HELPER_MODULE
58    if (key->polygon_stipple) {
59       /* get new shader that implements polygon stippling */
60       stipple_fs = util_pstipple_create_fragment_shader(&softpipe->pipe,
61                                                         curfs, &unit);
62       curfs = stipple_fs;
63    }
64 #endif
65 
66    /* codegen, create variant object */
67    var = softpipe_create_fs_variant_exec(softpipe, curfs);
68 
69    if (var) {
70       var->key = *key;
71       var->tokens = tgsi_dup_tokens(curfs->tokens);
72       var->stipple_sampler_unit = unit;
73 
74       tgsi_scan_shader(var->tokens, &var->info);
75 
76       /* See comments elsewhere about draw fragment shaders */
77 #if 0
78       /* draw's fs state */
79       var->draw_shader = draw_create_fragment_shader(softpipe->draw,
80                                                      &fs->shader);
81       if (!var->draw_shader) {
82          var->delete(var);
83          FREE((void *) var->tokens);
84          return NULL;
85       }
86 #endif
87 
88       /* insert variant into linked list */
89       var->next = fs->variants;
90       fs->variants = var;
91    }
92 
93    if (stipple_fs) {
94       FREE((void *) stipple_fs->tokens);
95       FREE(stipple_fs);
96    }
97 
98    return var;
99 }
100 
101 
102 struct sp_fragment_shader_variant *
softpipe_find_fs_variant(struct softpipe_context * sp,struct sp_fragment_shader * fs,const struct sp_fragment_shader_variant_key * key)103 softpipe_find_fs_variant(struct softpipe_context *sp,
104                          struct sp_fragment_shader *fs,
105                          const struct sp_fragment_shader_variant_key *key)
106 {
107    struct sp_fragment_shader_variant *var;
108 
109    for (var = fs->variants; var; var = var->next) {
110       if (memcmp(&var->key, key, sizeof(*key)) == 0) {
111          /* found it */
112          return var;
113       }
114    }
115 
116    return create_fs_variant(sp, fs, key);
117 }
118 
119 
120 static void *
softpipe_create_fs_state(struct pipe_context * pipe,const struct pipe_shader_state * templ)121 softpipe_create_fs_state(struct pipe_context *pipe,
122                          const struct pipe_shader_state *templ)
123 {
124    struct softpipe_context *softpipe = softpipe_context(pipe);
125    struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader);
126 
127    /* debug */
128    if (softpipe->dump_fs)
129       tgsi_dump(templ->tokens, 0);
130 
131    /* we need to keep a local copy of the tokens */
132    state->shader.tokens = tgsi_dup_tokens(templ->tokens);
133 
134    /* draw's fs state */
135    state->draw_shader = draw_create_fragment_shader(softpipe->draw,
136                                                     &state->shader);
137    if (!state->draw_shader) {
138       FREE((void *) state->shader.tokens);
139       FREE(state);
140       return NULL;
141    }
142 
143    return state;
144 }
145 
146 
147 static void
softpipe_bind_fs_state(struct pipe_context * pipe,void * fs)148 softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
149 {
150    struct softpipe_context *softpipe = softpipe_context(pipe);
151    struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs;
152 
153    if (softpipe->fs == fs)
154       return;
155 
156    draw_flush(softpipe->draw);
157 
158    softpipe->fs = fs;
159 
160    /* This depends on the current fragment shader and must always be
161     * re-validated before use.
162     */
163    softpipe->fs_variant = NULL;
164 
165    if (state)
166       draw_bind_fragment_shader(softpipe->draw,
167                                 state->draw_shader);
168    else
169       draw_bind_fragment_shader(softpipe->draw, NULL);
170 
171    softpipe->dirty |= SP_NEW_FS;
172 }
173 
174 
175 static void
softpipe_delete_fs_state(struct pipe_context * pipe,void * fs)176 softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
177 {
178    struct softpipe_context *softpipe = softpipe_context(pipe);
179    struct sp_fragment_shader *state = fs;
180    struct sp_fragment_shader_variant *var, *next_var;
181 
182    assert(fs != softpipe->fs);
183 
184    /* delete variants */
185    for (var = state->variants; var; var = next_var) {
186       next_var = var->next;
187 
188       assert(var != softpipe->fs_variant);
189 
190       /* See comments elsewhere about draw fragment shaders */
191 #if 0
192       draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
193 #endif
194 
195       var->delete(var, softpipe->fs_machine);
196    }
197 
198    draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
199 
200    FREE((void *) state->shader.tokens);
201    FREE(state);
202 }
203 
204 
205 static void *
softpipe_create_vs_state(struct pipe_context * pipe,const struct pipe_shader_state * templ)206 softpipe_create_vs_state(struct pipe_context *pipe,
207                          const struct pipe_shader_state *templ)
208 {
209    struct softpipe_context *softpipe = softpipe_context(pipe);
210    struct sp_vertex_shader *state;
211 
212    state = CALLOC_STRUCT(sp_vertex_shader);
213    if (state == NULL )
214       goto fail;
215 
216    /* copy shader tokens, the ones passed in will go away.
217     */
218    state->shader.tokens = tgsi_dup_tokens(templ->tokens);
219    if (state->shader.tokens == NULL)
220       goto fail;
221 
222    state->draw_data = draw_create_vertex_shader(softpipe->draw, templ);
223    if (state->draw_data == NULL)
224       goto fail;
225 
226    state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
227 
228    return state;
229 
230 fail:
231    if (state) {
232       FREE( (void *)state->shader.tokens );
233       FREE( state->draw_data );
234       FREE( state );
235    }
236    return NULL;
237 }
238 
239 
240 static void
softpipe_bind_vs_state(struct pipe_context * pipe,void * vs)241 softpipe_bind_vs_state(struct pipe_context *pipe, void *vs)
242 {
243    struct softpipe_context *softpipe = softpipe_context(pipe);
244 
245    softpipe->vs = (struct sp_vertex_shader *) vs;
246 
247    draw_bind_vertex_shader(softpipe->draw,
248                            (softpipe->vs ? softpipe->vs->draw_data : NULL));
249 
250    softpipe->dirty |= SP_NEW_VS;
251 }
252 
253 
254 static void
softpipe_delete_vs_state(struct pipe_context * pipe,void * vs)255 softpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
256 {
257    struct softpipe_context *softpipe = softpipe_context(pipe);
258 
259    struct sp_vertex_shader *state = (struct sp_vertex_shader *) vs;
260 
261    draw_delete_vertex_shader(softpipe->draw, state->draw_data);
262    FREE( (void *)state->shader.tokens );
263    FREE( state );
264 }
265 
266 
267 static void *
softpipe_create_gs_state(struct pipe_context * pipe,const struct pipe_shader_state * templ)268 softpipe_create_gs_state(struct pipe_context *pipe,
269                          const struct pipe_shader_state *templ)
270 {
271    struct softpipe_context *softpipe = softpipe_context(pipe);
272    struct sp_geometry_shader *state;
273 
274    state = CALLOC_STRUCT(sp_geometry_shader);
275    if (state == NULL )
276       goto fail;
277 
278    /* debug */
279    if (softpipe->dump_gs)
280       tgsi_dump(templ->tokens, 0);
281 
282    /* copy shader tokens, the ones passed in will go away.
283     */
284    state->shader.tokens = tgsi_dup_tokens(templ->tokens);
285    if (state->shader.tokens == NULL)
286       goto fail;
287 
288    state->draw_data = draw_create_geometry_shader(softpipe->draw, templ);
289    if (state->draw_data == NULL)
290       goto fail;
291 
292    state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
293 
294    return state;
295 
296 fail:
297    if (state) {
298       FREE( (void *)state->shader.tokens );
299       FREE( state->draw_data );
300       FREE( state );
301    }
302    return NULL;
303 }
304 
305 
306 static void
softpipe_bind_gs_state(struct pipe_context * pipe,void * gs)307 softpipe_bind_gs_state(struct pipe_context *pipe, void *gs)
308 {
309    struct softpipe_context *softpipe = softpipe_context(pipe);
310 
311    softpipe->gs = (struct sp_geometry_shader *)gs;
312 
313    draw_bind_geometry_shader(softpipe->draw,
314                              (softpipe->gs ? softpipe->gs->draw_data : NULL));
315 
316    softpipe->dirty |= SP_NEW_GS;
317 }
318 
319 
320 static void
softpipe_delete_gs_state(struct pipe_context * pipe,void * gs)321 softpipe_delete_gs_state(struct pipe_context *pipe, void *gs)
322 {
323    struct softpipe_context *softpipe = softpipe_context(pipe);
324 
325    struct sp_geometry_shader *state =
326       (struct sp_geometry_shader *)gs;
327 
328    draw_delete_geometry_shader(softpipe->draw,
329                                (state) ? state->draw_data : 0);
330 
331    FREE((void *) state->shader.tokens);
332    FREE(state);
333 }
334 
335 
336 static void
softpipe_set_constant_buffer(struct pipe_context * pipe,uint shader,uint index,struct pipe_constant_buffer * cb)337 softpipe_set_constant_buffer(struct pipe_context *pipe,
338                              uint shader, uint index,
339                              struct pipe_constant_buffer *cb)
340 {
341    struct softpipe_context *softpipe = softpipe_context(pipe);
342    struct pipe_resource *constants = cb ? cb->buffer : NULL;
343    unsigned size;
344    const void *data;
345 
346    if (cb && cb->user_buffer) {
347       constants = softpipe_user_buffer_create(pipe->screen,
348                                               (void *) cb->user_buffer,
349                                               cb->buffer_size,
350                                               PIPE_BIND_CONSTANT_BUFFER);
351    }
352 
353    size = constants ? constants->width0 : 0;
354    data = constants ? softpipe_resource(constants)->data : NULL;
355 
356    assert(shader < PIPE_SHADER_TYPES);
357 
358    draw_flush(softpipe->draw);
359 
360    /* note: reference counting */
361    pipe_resource_reference(&softpipe->constants[shader][index], constants);
362 
363    if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
364       draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size);
365    }
366 
367    softpipe->mapped_constants[shader][index] = data;
368    softpipe->const_buffer_size[shader][index] = size;
369 
370    softpipe->dirty |= SP_NEW_CONSTANTS;
371 
372    if (cb && cb->user_buffer) {
373       pipe_resource_reference(&constants, NULL);
374    }
375 }
376 
377 
378 void
softpipe_init_shader_funcs(struct pipe_context * pipe)379 softpipe_init_shader_funcs(struct pipe_context *pipe)
380 {
381    pipe->create_fs_state = softpipe_create_fs_state;
382    pipe->bind_fs_state   = softpipe_bind_fs_state;
383    pipe->delete_fs_state = softpipe_delete_fs_state;
384 
385    pipe->create_vs_state = softpipe_create_vs_state;
386    pipe->bind_vs_state   = softpipe_bind_vs_state;
387    pipe->delete_vs_state = softpipe_delete_vs_state;
388 
389    pipe->create_gs_state = softpipe_create_gs_state;
390    pipe->bind_gs_state   = softpipe_bind_gs_state;
391    pipe->delete_gs_state = softpipe_delete_gs_state;
392 
393    pipe->set_constant_buffer = softpipe_set_constant_buffer;
394 }
395