2 * Copyright © 2012 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 * Custom functions for marshalling GL calls from the main thread to a worker
27 * thread when automatic code generation isn't appropriate.
32 #include "marshal_generated.h"
36 struct marshal_cmd_Flush
38 struct marshal_cmd_base cmd_base
;
43 _mesa_unmarshal_Flush(struct gl_context
*ctx
,
44 const struct marshal_cmd_Flush
*cmd
)
46 CALL_Flush(ctx
->CurrentServerDispatch
, ());
51 _mesa_marshal_Flush(void)
53 GET_CURRENT_CONTEXT(ctx
);
54 struct marshal_cmd_Flush
*cmd
=
55 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_Flush
,
56 sizeof(struct marshal_cmd_Flush
));
58 _mesa_post_marshal_hook(ctx
);
60 /* Flush() needs to be handled specially. In addition to telling the
61 * background thread to flush, we need to ensure that our own buffer is
62 * submitted to the background thread so that it will complete in a finite
65 _mesa_glthread_flush_batch(ctx
);
69 struct marshal_cmd_ShaderSource
71 struct marshal_cmd_base cmd_base
;
74 /* Followed by GLint length[count], then the contents of all strings,
81 _mesa_unmarshal_ShaderSource(struct gl_context
*ctx
,
82 const struct marshal_cmd_ShaderSource
*cmd
)
84 const GLint
*cmd_length
= (const GLint
*) (cmd
+ 1);
85 const GLchar
*cmd_strings
= (const GLchar
*) (cmd_length
+ cmd
->count
);
86 /* TODO: how to deal with malloc failure? */
87 const GLchar
* *string
= malloc(cmd
->count
* sizeof(const GLchar
*));
90 for (i
= 0; i
< cmd
->count
; ++i
) {
91 string
[i
] = cmd_strings
;
92 cmd_strings
+= cmd_length
[i
];
94 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
95 (cmd
->shader
, cmd
->count
, string
, cmd_length
));
101 measure_ShaderSource_strings(GLsizei count
, const GLchar
* const *string
,
102 const GLint
*length_in
, GLint
*length_out
)
105 size_t total_string_length
= 0;
107 for (i
= 0; i
< count
; ++i
) {
108 if (length_in
== NULL
|| length_in
[i
] < 0) {
110 length_out
[i
] = strlen(string
[i
]);
112 length_out
[i
] = length_in
[i
];
114 total_string_length
+= length_out
[i
];
116 return total_string_length
;
121 _mesa_marshal_ShaderSource(GLuint shader
, GLsizei count
,
122 const GLchar
* const *string
, const GLint
*length
)
124 /* TODO: how to report an error if count < 0? */
126 GET_CURRENT_CONTEXT(ctx
);
127 /* TODO: how to deal with malloc failure? */
128 const size_t fixed_cmd_size
= sizeof(struct marshal_cmd_ShaderSource
);
129 STATIC_ASSERT(sizeof(struct marshal_cmd_ShaderSource
) % sizeof(GLint
) == 0);
130 size_t length_size
= count
* sizeof(GLint
);
131 GLint
*length_tmp
= malloc(length_size
);
132 size_t total_string_length
=
133 measure_ShaderSource_strings(count
, string
, length
, length_tmp
);
134 size_t total_cmd_size
= fixed_cmd_size
+ length_size
+ total_string_length
;
136 if (total_cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
137 struct marshal_cmd_ShaderSource
*cmd
=
138 _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_ShaderSource
,
140 GLint
*cmd_length
= (GLint
*) (cmd
+ 1);
141 GLchar
*cmd_strings
= (GLchar
*) (cmd_length
+ count
);
144 cmd
->shader
= shader
;
146 memcpy(cmd_length
, length_tmp
, length_size
);
147 for (i
= 0; i
< count
; ++i
) {
148 memcpy(cmd_strings
, string
[i
], cmd_length
[i
]);
149 cmd_strings
+= cmd_length
[i
];
151 _mesa_post_marshal_hook(ctx
);
153 _mesa_glthread_finish(ctx
);
154 CALL_ShaderSource(ctx
->CurrentServerDispatch
,
155 (shader
, count
, string
, length_tmp
));
161 /* BindBufferBase: marshalled asynchronously */
162 struct marshal_cmd_BindBufferBase
164 struct marshal_cmd_base cmd_base
;
170 _mesa_unmarshal_BindBufferBase(struct gl_context
*ctx
, const struct marshal_cmd_BindBufferBase
*cmd
)
172 const GLenum target
= cmd
->target
;
173 const GLuint index
= cmd
->index
;
174 const GLuint buffer
= cmd
->buffer
;
175 CALL_BindBufferBase(ctx
->CurrentServerDispatch
, (target
, index
, buffer
));
178 /** Tracks the current bindings for the vertex array and index array buffers.
180 * This is part of what we need to enable glthread on compat-GL contexts that
181 * happen to use VBOs, without also supporting the full tracking of VBO vs
182 * user vertex array bindings per attribute on each vertex array for
183 * determining what to upload at draw call time.
185 * Note that GL core makes it so that a buffer binding with an invalid handle
186 * in the "buffer" parameter will throw an error, and then a
187 * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
188 * However, in GL core the draw call would throw an error as well, so we don't
189 * really care if our tracking is wrong for this case -- we never need to
190 * marshal user data for draw calls, and the unmarshal will just generate an
191 * error or not as appropriate.
193 * For compatibility GL, we do need to accurately know whether the draw call
194 * on the unmarshal side will dereference a user pointer or load data from a
195 * VBO per vertex. That would make it seem like we need to track whether a
196 * "buffer" is valid, so that we can know when an error will be generated
197 * instead of updating the binding. However, compat GL has the ridiculous
198 * feature that if you pass a bad name, it just gens a buffer object for you,
199 * so we escape without having to know if things are valid or not.
202 track_vbo_binding(struct gl_context
*ctx
, GLenum target
, GLuint buffer
)
204 struct glthread_state
*glthread
= ctx
->GLThread
;
207 case GL_ARRAY_BUFFER
:
208 glthread
->vertex_array_is_vbo
= (buffer
!= 0);
210 case GL_ELEMENT_ARRAY_BUFFER
:
211 /* The current element array buffer binding is actually tracked in the
212 * vertex array object instead of the context, so this would need to
213 * change on vertex array object updates.
215 glthread
->element_array_is_vbo
= (buffer
!= 0);
221 struct marshal_cmd_BindBuffer
223 struct marshal_cmd_base cmd_base
;
229 * This is just like the code-generated glBindBuffer() support, except that we
230 * call track_vbo_binding().
233 _mesa_unmarshal_BindBuffer(struct gl_context
*ctx
,
234 const struct marshal_cmd_BindBuffer
*cmd
)
236 const GLenum target
= cmd
->target
;
237 const GLuint buffer
= cmd
->buffer
;
238 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));
241 _mesa_marshal_BindBuffer(GLenum target
, GLuint buffer
)
243 GET_CURRENT_CONTEXT(ctx
);
244 size_t cmd_size
= sizeof(struct marshal_cmd_BindBuffer
);
245 struct marshal_cmd_BindBuffer
*cmd
;
246 debug_print_marshal("BindBuffer");
248 track_vbo_binding(ctx
, target
, buffer
);
250 if (cmd_size
<= MARSHAL_MAX_CMD_SIZE
) {
251 cmd
= _mesa_glthread_allocate_command(ctx
, DISPATCH_CMD_BindBuffer
,
253 cmd
->target
= target
;
254 cmd
->buffer
= buffer
;
255 _mesa_post_marshal_hook(ctx
);
257 _mesa_glthread_finish(ctx
);
258 CALL_BindBuffer(ctx
->CurrentServerDispatch
, (target
, buffer
));