]> git.cworth.org Git - vogl/blob - src/voglcommon/vogl_arb_program_state.cpp
Initial vogl checkin
[vogl] / src / voglcommon / vogl_arb_program_state.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 // File: vogl_arb_program_state.cpp
27 #include "vogl_arb_program_state.h"
28
29 static const char *vogl_get_arb_program_target_name(GLenum target)
30 {
31     VOGL_FUNC_TRACER
32
33     VOGL_ASSERT((target == GL_VERTEX_PROGRAM_ARB) || (target == GL_FRAGMENT_PROGRAM_ARB));
34     return (target == GL_VERTEX_PROGRAM_ARB) ? "vertex" : "fragment";
35 }
36
37 vogl_arb_program_state::vogl_arb_program_state()
38     : m_snapshot_handle(0),
39       m_target(GL_NONE),
40       m_error_position(-1),
41       m_is_native(false),
42       m_num_instructions(0),
43       m_program_format(GL_NONE),
44       m_is_valid(false)
45 {
46     VOGL_FUNC_TRACER
47 }
48
49 vogl_arb_program_state::~vogl_arb_program_state()
50 {
51     VOGL_FUNC_TRACER
52 }
53
54 GLint vogl_arb_program_state::get_program_int(GLenum pname) const
55 {
56     VOGL_FUNC_TRACER
57
58     GLint val = 0;
59     GL_ENTRYPOINT(glGetProgramivARB)(m_target, pname, &val);
60     VOGL_CHECK_GL_ERROR;
61     return val;
62 }
63
64 bool vogl_arb_program_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
65 {
66     VOGL_FUNC_TRACER
67
68     VOGL_NOTE_UNUSED(context_info);
69     VOGL_NOTE_UNUSED(remapper);
70
71     clear();
72
73     VOGL_CHECK_GL_ERROR;
74
75     VOGL_ASSERT(handle <= cUINT32_MAX);
76
77     m_snapshot_handle = static_cast<GLuint>(handle);
78     m_target = target;
79
80     if (m_target != GL_NONE)
81     {
82         vogl_scoped_state_saver state_saver(cGSTARBVertexProgram, cGSTARBFragmentProgram);
83
84         GL_ENTRYPOINT(glBindProgramARB)(m_target, m_snapshot_handle);
85         VOGL_CHECK_GL_ERROR;
86
87         m_program_format = get_program_int(GL_PROGRAM_FORMAT_ARB);
88
89         // Note: there doesn't seem a way to query if this program was compiled sucessfully (without trying to recompile it)?
90         m_num_instructions = get_program_int(GL_PROGRAM_INSTRUCTIONS_ARB);
91         m_is_native = get_program_int(GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB) != 0;
92
93         int program_len = get_program_int(GL_PROGRAM_LENGTH_ARB);
94         if ((program_len < 0) || (!m_program_string.try_resize(program_len)))
95         {
96             clear();
97             return false;
98         }
99
100         if (program_len)
101         {
102             GL_ENTRYPOINT(glGetProgramStringARB)(m_target, GL_PROGRAM_STRING_ARB, m_program_string.get_ptr());
103             VOGL_CHECK_GL_ERROR;
104         }
105
106         int num_local_params = get_program_int(GL_PROGRAM_PARAMETERS_ARB);
107         if ((num_local_params < 0) || (!m_local_params.try_resize(num_local_params)))
108         {
109             clear();
110             return false;
111         }
112
113         for (int i = 0; i < num_local_params; i++)
114         {
115             GL_ENTRYPOINT(glGetProgramLocalParameterfvARB)(m_target, i, m_local_params[i].get_ptr());
116             VOGL_CHECK_GL_ERROR;
117         }
118     }
119
120     m_is_valid = true;
121
122     return true;
123 }
124
125 bool vogl_arb_program_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
126 {
127     VOGL_FUNC_TRACER
128
129     VOGL_NOTE_UNUSED(context_info);
130
131     VOGL_CHECK_GL_ERROR;
132
133     if (!m_is_valid)
134         return false;
135
136     bool created_handle = false;
137     VOGL_NOTE_UNUSED(created_handle);
138
139     VOGL_ASSERT(static_cast<GLuint>(handle) == handle);
140
141     GLuint handle32 = static_cast<GLuint>(handle);
142
143     if (!handle32)
144     {
145         GL_ENTRYPOINT(glGenProgramsARB)(1, &handle32);
146         if ((vogl_check_gl_error()) || (!handle32))
147             return false;
148
149         handle = handle32;
150
151         remapper.declare_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle, handle, m_target);
152         VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle) == handle);
153
154         created_handle = true;
155     }
156
157     if (m_target != GL_NONE)
158     {
159         vogl_scoped_state_saver state_saver(cGSTARBVertexProgram, cGSTARBFragmentProgram);
160
161         GL_ENTRYPOINT(glBindProgramARB)(m_target, handle32);
162         VOGL_CHECK_GL_ERROR;
163
164         if (m_program_string.size() && (m_program_format != GL_NONE))
165         {
166             GL_ENTRYPOINT(glProgramStringARB)(m_target, m_program_format, m_program_string.size(), m_program_string.get_ptr());
167
168             bool failed = vogl_check_gl_error();
169
170             m_error_position = vogl_get_gl_integer(GL_PROGRAM_ERROR_POSITION_ARB);
171             m_is_native = get_program_int(GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB) != 0;
172
173             if ((failed) || (m_error_position >= 0) || (!m_is_native))
174             {
175                 const GLubyte *pError_string = NULL;
176                 pError_string = static_cast<const GLubyte *>(GL_ENTRYPOINT(glGetString)(GL_PROGRAM_ERROR_STRING_ARB));
177                 VOGL_CHECK_GL_ERROR;
178
179                 m_error_string.set(pError_string ? reinterpret_cast<const char *>(pError_string) : "");
180
181                 vogl_error_printf("%s: Failed restoring ARB %s shader, GL handle %u, error position %i, is native: %u, error string: %s\n", VOGL_METHOD_NAME,
182                                  vogl_get_arb_program_target_name(m_target), handle32, m_error_position, m_is_native, m_error_string.get_ptr());
183             }
184         }
185
186         for (uint i = 0; i < m_local_params.size(); i++)
187         {
188             GL_ENTRYPOINT(glProgramLocalParameter4fvARB)(m_target, i, m_local_params[i].get_ptr());
189             VOGL_CHECK_GL_ERROR;
190         }
191     }
192
193     return true;
194 }
195
196 bool vogl_arb_program_state::remap_handles(vogl_handle_remapper &remapper)
197 {
198     VOGL_FUNC_TRACER
199
200     if (!m_is_valid)
201         return false;
202
203     uint replay_handle = m_snapshot_handle;
204     VOGL_NOTE_UNUSED(replay_handle);
205
206     uint trace_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_snapshot_handle));
207
208     m_snapshot_handle = trace_handle;
209
210     return true;
211 }
212
213 void vogl_arb_program_state::clear()
214 {
215     VOGL_FUNC_TRACER
216
217     m_snapshot_handle = 0;
218     m_target = GL_NONE;
219
220     m_error_position = -1;
221     m_error_string.clear();
222     m_is_native = false;
223     m_program_format = GL_NONE;
224     m_num_instructions = 0;
225
226     m_program_string.clear();
227     m_local_params.clear();
228
229     m_is_valid = false;
230 }
231
232 bool vogl_arb_program_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
233 {
234     VOGL_FUNC_TRACER
235
236     if (!m_is_valid)
237         return false;
238
239     node.add_key_value("snapshot_handle", m_snapshot_handle);
240     node.add_key_value("target", g_gl_enums.find_gl_name(m_target));
241     node.add_key_value("error_position", m_error_position);
242     node.add_key_value("error_string", m_error_string);
243     node.add_key_value("is_native", m_is_native);
244     node.add_key_value("num_instructions", m_num_instructions);
245     node.add_key_value("program_format", g_gl_enums.find_gl_name(m_program_format));
246
247     if (m_program_string.size())
248     {
249         dynamic_string prefix(cVarArg, "arb_%s_program", vogl_get_arb_program_target_name(m_target));
250
251         dynamic_string id(blob_manager.add_buf_compute_unique_id(m_program_string.get_ptr(), m_program_string.size(), prefix.get_ptr(), "txt"));
252         if (id.is_empty())
253             return false;
254
255         node.add_key_value("program_string", id);
256     }
257
258     if (m_local_params.size())
259     {
260         json_node &param_array = node.add_array("local_params");
261         for (uint i = 0; i < m_local_params.size(); i++)
262             if (!vogl_json_serialize_vec4F(param_array.add_array(), m_local_params[i]))
263                 return false;
264     }
265
266     return true;
267 }
268
269 bool vogl_arb_program_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
270 {
271     VOGL_FUNC_TRACER
272
273     clear();
274
275     if (!node.is_object())
276         return false;
277
278     m_snapshot_handle = node.value_as_int("snapshot_handle");
279     m_target = vogl_get_json_value_as_enum(node, "target");
280     m_error_position = node.value_as_int("error_position");
281     m_error_string = node.value_as_string("error_string");
282     m_is_native = node.value_as_bool("is_native");
283     m_num_instructions = node.value_as_int("num_instructions");
284     m_program_format = vogl_get_json_value_as_enum(node, "program_format");
285
286     if (node.has_key("program_string"))
287     {
288         if (!blob_manager.get(node.value_as_string("program_string"), m_program_string))
289         {
290             clear();
291             return false;
292         }
293     }
294
295     const json_node *pParams_node = node.find_child_array("local_params");
296     if (pParams_node)
297     {
298         if (!pParams_node->are_all_children_arrays())
299             return false;
300
301         m_local_params.resize(pParams_node->size());
302         for (uint i = 0; i < pParams_node->size(); i++)
303         {
304             if (!vogl_json_deserialize_vec4F(*pParams_node->get_child(i), m_local_params[i]))
305             {
306                 clear();
307                 return false;
308             }
309         }
310     }
311
312     m_is_valid = true;
313
314     return true;
315 }
316
317 bool vogl_arb_program_state::compare_restorable_state(const vogl_gl_object_state &rhs_obj) const
318 {
319     VOGL_FUNC_TRACER
320
321     if ((!m_is_valid) || (!rhs_obj.is_valid()))
322         return false;
323
324     if (get_type() != rhs_obj.get_type())
325         return false;
326
327     const vogl_arb_program_state &rhs = static_cast<const vogl_arb_program_state &>(rhs_obj);
328
329     if (this == &rhs)
330         return true;
331
332 #define CMP(x)      \
333     if (x != rhs.x) \
334         return false;
335     CMP(m_target);
336     CMP(m_program_format);
337     CMP(m_program_string);
338     CMP(m_local_params.size());
339 #undef CMP
340
341     for (uint i = 0; i < m_local_params.size(); i++)
342         if (!m_local_params[i].equal_tol(rhs.m_local_params[i], .00125f))
343             return false;
344
345     return true;
346 }
347
348 vogl_arb_program_environment_state::vogl_arb_program_environment_state()
349     : m_is_valid(false)
350 {
351     VOGL_FUNC_TRACER
352
353     VOGL_ASSUME(cNumTargets == 2);
354
355     utils::zero_object(m_cur_programs);
356 }
357
358 vogl_arb_program_environment_state::~vogl_arb_program_environment_state()
359 {
360     VOGL_FUNC_TRACER
361 }
362
363 bool vogl_arb_program_environment_state::snapshot(const vogl_context_info &context_info)
364 {
365     VOGL_FUNC_TRACER
366
367     clear();
368
369     VOGL_CHECK_GL_ERROR;
370
371     for (uint i = 0; i < cNumTargets; i++)
372     {
373         GLenum target = get_target_enum(i);
374
375         GL_ENTRYPOINT(glGetProgramivARB)(target, GL_PROGRAM_BINDING_ARB, reinterpret_cast<GLint *>(&m_cur_programs[i]));
376         VOGL_CHECK_GL_ERROR;
377
378         GLuint num = (i == cVertexTarget) ? context_info.get_max_arb_vertex_program_env_params() : context_info.get_max_arb_fragment_program_env_params();
379
380         m_env_params[i].resize(num);
381         for (uint j = 0; j < num; j++)
382         {
383             GL_ENTRYPOINT(glGetProgramEnvParameterfvARB)(target, j, m_env_params[i][j].get_ptr());
384             VOGL_CHECK_GL_ERROR;
385         }
386     }
387
388     m_is_valid = true;
389
390     return true;
391 }
392
393 bool vogl_arb_program_environment_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &trace_to_replay_remapper) const
394 {
395     VOGL_FUNC_TRACER
396
397     if (!m_is_valid)
398     {
399         VOGL_ASSERT_ALWAYS;
400         return false;
401     }
402
403     VOGL_CHECK_GL_ERROR;
404
405     for (uint i = 0; i < cNumTargets; i++)
406     {
407         GLenum target = get_target_enum(i);
408
409         GLuint binding = static_cast<GLuint>(trace_to_replay_remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, m_cur_programs[i]));
410
411         GL_ENTRYPOINT(glBindProgramARB)(target, binding);
412         VOGL_CHECK_GL_ERROR;
413
414         GLuint num = (i == cVertexTarget) ? context_info.get_max_arb_vertex_program_env_params() : context_info.get_max_arb_fragment_program_env_params();
415
416         if (m_env_params[i].size() > num)
417             vogl_error_printf("%s: Context only supports %u max ARB program env programs, but the snapshot has %u params\n", VOGL_METHOD_NAME, num, m_env_params[i].size());
418
419         num = math::minimum<uint>(num, m_env_params[i].size());
420
421         for (uint j = 0; j < num; j++)
422         {
423             GL_ENTRYPOINT(glProgramEnvParameter4fvARB)(target, j, m_env_params[i][j].get_ptr());
424             VOGL_CHECK_GL_ERROR;
425         }
426     }
427
428     return true;
429 }
430
431 bool vogl_arb_program_environment_state::remap_handles(vogl_handle_remapper &remapper)
432 {
433     VOGL_FUNC_TRACER
434
435     if (!m_is_valid)
436     {
437         VOGL_ASSERT_ALWAYS;
438         return false;
439     }
440
441     for (uint target = 0; target < cNumTargets; target++)
442     {
443         uint replay_handle = m_cur_programs[target];
444         if (replay_handle)
445         {
446             uint trace_handle = static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_PROGRAM_ARB, replay_handle));
447
448             m_cur_programs[target] = trace_handle;
449         }
450     }
451
452     return true;
453 }
454
455 void vogl_arb_program_environment_state::clear()
456 {
457     VOGL_FUNC_TRACER
458
459     utils::zero_object(m_cur_programs);
460
461     m_is_valid = false;
462
463     for (uint i = 0; i < cNumTargets; i++)
464         m_env_params[i].clear();
465 }
466
467 bool vogl_arb_program_environment_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
468 {
469     VOGL_FUNC_TRACER
470
471     VOGL_NOTE_UNUSED(blob_manager);
472
473     if (!m_is_valid)
474     {
475         VOGL_ASSERT_ALWAYS;
476         return false;
477     }
478
479     for (uint target = 0; target < cNumTargets; target++)
480     {
481         json_node &state_node = node.add_object(get_target_index_name(target));
482
483         state_node.add_key_value("cur_program", m_cur_programs[target]);
484
485         json_node &env_params_node = state_node.add_array("env_params");
486
487         for (uint j = 0; j < m_env_params[target].size(); j++)
488             if (!vogl_json_serialize_vec4F(env_params_node.add_array(), m_env_params[target][j]))
489                 return false;
490     }
491
492     return true;
493 }
494
495 bool vogl_arb_program_environment_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
496 {
497     VOGL_FUNC_TRACER
498
499     VOGL_NOTE_UNUSED(blob_manager);
500
501     clear();
502
503     if (!node.is_object())
504         return false;
505
506     for (uint target = 0; target < cNumTargets; target++)
507     {
508         const json_node *pState = node.find_child_object(get_target_index_name(target));
509         if (!pState)
510             continue;
511
512         m_cur_programs[target] = pState->value_as_uint32("cur_program");
513
514         const json_node *pArray = pState->find_child_array("env_params");
515         if (pArray)
516         {
517             m_env_params[target].resize(pArray->size());
518             for (uint i = 0; i < pArray->size(); i++)
519             {
520                 if (!vogl_json_deserialize_vec4F(*pArray->get_value_as_array(i), m_env_params[target][i]))
521                 {
522                     clear();
523                     return false;
524                 }
525             }
526         }
527     }
528
529     m_is_valid = true;
530
531     return true;
532 }
533
534 bool vogl_arb_program_environment_state::compare_restorable_state(const vogl_arb_program_environment_state &rhs) const
535 {
536     VOGL_FUNC_TRACER
537
538     if (m_is_valid != rhs.m_is_valid)
539         return false;
540
541     if (!m_is_valid)
542         return true;
543
544     for (uint i = 0; i < cNumTargets; i++)
545     {
546         if (m_cur_programs[i] != rhs.m_cur_programs[i])
547             return false;
548
549         if (m_env_params[i].size() != rhs.m_env_params[i].size())
550             return false;
551
552         for (uint j = 0; j < m_env_params[i].size(); j++)
553             if (!m_env_params[i][j].equal_tol(rhs.m_env_params[i][j], .00125f))
554                 return false;
555     }
556
557     return true;
558 }