Harbor

Changelog 2bcdb57323a2

pin opengl handle guards

@sky · 1 month ago · parent f68de9cedde9
1 added 2 modified 0 deleted
gpu/backend/opengl/gl_frame.odin +4 -4 modified
39 unchanged lines hidden
40 40 begin_default_pass_opengl(ctx, desc.clear_color)
41 41 return
42 42 }
43 - fb := &g_gl.framebuffers[desc.framebuffer]
44 - if !fb.active {
43 + fb, fb_ok := framebuffer_entry(desc.framebuffer)
44 + if !fb_ok {
45 45 log.error("gpu/opengl: invalid framebuffer")
46 46 return
47 47 }
2 unchanged lines hidden
50 50 gl.ClearColor(desc.clear_color[0], desc.clear_color[1], desc.clear_color[2], desc.clear_color[3])
51 51 gl.ClearDepth(f64(desc.clear_depth))
52 52 mask := u32(0)
53 - pass := &g_gl.render_passes[desc.pass]
54 - if pass.active {
53 + pass, pass_ok := render_pass_entry(desc.pass)
54 + if pass_ok {
55 55 if pass.desc.has_color do mask |= gl.COLOR_BUFFER_BIT
56 56 if pass.desc.has_depth do mask |= gl.DEPTH_BUFFER_BIT
57 57 } else {
23 unchanged lines hidden
gpu/backend/opengl/gl_ops.odin +117 -77 modified
61 unchanged lines hidden
62 62 return bk.NULL_SAMPLER, false
63 63 }
64 64
65 + active_pool_entry :: proc(pool: ^[$N]$E, handle: $T) -> (^E, bool) {
66 + idx, ok := bk.handle_index(handle, N)
67 + if !ok do return nil, false
68 + entry := &pool[idx]
69 + if !entry.active do return nil, false
70 + return entry, true
71 + }
72 +
73 + buffer_entry :: proc(handle: bk.Buffer_Handle) -> (^GL_Buffer_Entry, bool) {
74 + if g_gl == nil do return nil, false
75 + return active_pool_entry(&g_gl.buffers, handle)
76 + }
77 +
78 + texture_entry :: proc(handle: bk.Texture_Handle) -> (^GL_Texture_Entry, bool) {
79 + if g_gl == nil do return nil, false
80 + return active_pool_entry(&g_gl.textures, handle)
81 + }
82 +
83 + shader_entry :: proc(handle: bk.Shader_Handle) -> (^GL_Shader_Entry, bool) {
84 + if g_gl == nil do return nil, false
85 + return active_pool_entry(&g_gl.shaders, handle)
86 + }
87 +
88 + pipeline_entry :: proc(handle: bk.Pipeline_Handle) -> (^GL_Pipeline_Entry, bool) {
89 + if g_gl == nil do return nil, false
90 + return active_pool_entry(&g_gl.pipelines, handle)
91 + }
92 +
93 + descriptor_entry :: proc(handle: bk.Descriptor_Handle) -> (^GL_Descriptor_Entry, bool) {
94 + if g_gl == nil do return nil, false
95 + return active_pool_entry(&g_gl.descriptors, handle)
96 + }
97 +
98 + descriptor_entry_of_kind :: proc(handle: bk.Descriptor_Handle, kind: Descriptor_Kind) -> (^GL_Descriptor_Entry, bool) {
99 + entry, ok := descriptor_entry(handle)
100 + if !ok || entry.kind != kind do return nil, false
101 + return entry, true
102 + }
103 +
104 + render_pass_entry :: proc(handle: bk.Render_Pass_Handle) -> (^GL_Render_Pass_Entry, bool) {
105 + if g_gl == nil do return nil, false
106 + return active_pool_entry(&g_gl.render_passes, handle)
107 + }
108 +
109 + framebuffer_entry :: proc(handle: bk.Framebuffer_Handle) -> (^GL_Framebuffer_Entry, bool) {
110 + if g_gl == nil do return nil, false
111 + return active_pool_entry(&g_gl.framebuffers, handle)
112 + }
113 +
114 + sampler_entry :: proc(handle: bk.Sampler_Handle) -> (^GL_Sampler_Entry, bool) {
115 + if g_gl == nil do return nil, false
116 + return active_pool_entry(&g_gl.samplers, handle)
117 + }
118 +
65 119 create_buffer_opengl :: proc(desc: bk.Buffer_Desc) -> (bk.Buffer_Handle, bool) {
66 120 handle, ok := alloc_buffer_handle()
67 121 if !ok do return bk.NULL_BUFFER, false
37 unchanged lines hidden
105 159 }
106 160
107 161 destroy_buffer_opengl :: proc(handle: bk.Buffer_Handle) {
108 - if handle == bk.NULL_BUFFER do return
109 - entry := &g_gl.buffers[handle]
110 - if !entry.active do return
162 + entry, ok := buffer_entry(handle)
163 + if !ok do return
111 164 if entry.id != 0 {
112 165 id := entry.id
113 166 gl.DeleteBuffers(1, &id)
2 unchanged lines hidden
116 169 }
117 170
118 171 map_buffer_opengl :: proc(handle: bk.Buffer_Handle) -> rawptr {
119 - if handle == bk.NULL_BUFFER do return nil
120 - entry := &g_gl.buffers[handle]
121 - if !entry.active do return nil
172 + entry, ok := buffer_entry(handle)
173 + if !ok do return nil
122 174 ptr := gl.MapNamedBufferRange(entry.id, 0, int(entry.size), gl.MAP_WRITE_BIT | gl.MAP_INVALIDATE_BUFFER_BIT)
123 175 entry.mapped_ptr = ptr
124 176 return ptr
125 177 }
126 178
127 179 unmap_buffer_opengl :: proc(handle: bk.Buffer_Handle) {
128 - if handle == bk.NULL_BUFFER do return
129 - entry := &g_gl.buffers[handle]
130 - if !entry.active || entry.mapped_ptr == nil do return
180 + entry, ok := buffer_entry(handle)
181 + if !ok || entry.mapped_ptr == nil do return
131 182 gl.UnmapNamedBuffer(entry.id)
132 183 entry.mapped_ptr = nil
133 184 }
134 185
135 186 get_buffer_mapped_opengl :: proc(handle: bk.Buffer_Handle) -> rawptr {
136 - if handle == bk.NULL_BUFFER do return nil
137 - entry := &g_gl.buffers[handle]
138 - if !entry.active do return nil
187 + entry, ok := buffer_entry(handle)
188 + if !ok do return nil
139 189 if entry.mapped_ptr == nil do return map_buffer_opengl(handle)
140 190 return entry.mapped_ptr
141 191 }
142 192
143 193 bind_vertex_buffer_opengl :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {
144 194 if handle == bk.NULL_BUFFER || g_gl.current_pipeline == bk.NULL_PIPELINE do return
145 - buffer := &g_gl.buffers[handle]
146 - pipeline := &g_gl.pipelines[g_gl.current_pipeline]
147 - if !buffer.active || !pipeline.active || pipeline.vao == 0 do return
195 + buffer, buffer_ok := buffer_entry(handle)
196 + pipeline, pipeline_ok := pipeline_entry(g_gl.current_pipeline)
197 + if !buffer_ok || !pipeline_ok || pipeline.vao == 0 do return
148 198 gl.VertexArrayVertexBuffer(pipeline.vao, 0, buffer.id, 0, i32(pipeline.vertex_stride))
149 199 }
150 200
151 201 bind_index_buffer_opengl :: proc(ctx: bk.Frame_Context, handle: bk.Buffer_Handle) {
152 202 if handle == bk.NULL_BUFFER || g_gl.current_pipeline == bk.NULL_PIPELINE do return
153 - buffer := &g_gl.buffers[handle]
154 - pipeline := &g_gl.pipelines[g_gl.current_pipeline]
155 - if !buffer.active || !pipeline.active || pipeline.vao == 0 do return
203 + buffer, buffer_ok := buffer_entry(handle)
204 + pipeline, pipeline_ok := pipeline_entry(g_gl.current_pipeline)
205 + if !buffer_ok || !pipeline_ok || pipeline.vao == 0 do return
156 206 gl.VertexArrayElementBuffer(pipeline.vao, buffer.id)
157 207 }
158 208
36 unchanged lines hidden
195 245 }
196 246
197 247 destroy_texture_opengl :: proc(handle: bk.Texture_Handle) {
198 - if handle == bk.NULL_TEXTURE do return
199 - entry := &g_gl.textures[handle]
200 - if !entry.active do return
248 + entry, ok := texture_entry(handle)
249 + if !ok do return
201 250 if entry.id != 0 {
202 251 id := entry.id
203 252 gl.DeleteTextures(1, &id)
6 unchanged lines hidden
210 259 }
211 260
212 261 create_image_view_opengl :: proc(texture: bk.Texture_Handle, format: bk.Format, aspect: bk.Image_Aspect_Flags) -> bool {
213 - if texture == bk.NULL_TEXTURE do return false
214 - entry := &g_gl.textures[texture]
215 - return entry.active
262 + _, ok := texture_entry(texture)
263 + return ok
216 264 }
217 265
218 266 create_sampler_opengl :: proc(desc: bk.Sampler_Desc) -> (bk.Sampler_Handle, bool) {
17 unchanged lines hidden
236 284 }
237 285
238 286 destroy_sampler_opengl :: proc(handle: bk.Sampler_Handle) {
239 - if handle == bk.NULL_SAMPLER do return
240 - entry := &g_gl.samplers[handle]
241 - if !entry.active do return
287 + entry, ok := sampler_entry(handle)
288 + if !ok do return
242 289 if entry.id != 0 {
243 290 id := entry.id
244 291 gl.DeleteSamplers(1, &id)
45 unchanged lines hidden
290 337 }
291 338
292 339 destroy_shader_opengl :: proc(handle: bk.Shader_Handle) {
293 - if handle == bk.NULL_SHADER do return
294 - entry := &g_gl.shaders[handle]
295 - if !entry.active do return
340 + entry, ok := shader_entry(handle)
341 + if !ok do return
296 342 if entry.id != 0 do gl.DeleteShader(entry.id)
297 343 entry^ = {}
298 344 }
3 unchanged lines hidden
302 348 log.error("gpu/opengl: graphics pipeline requires vertex and fragment shaders")
303 349 return bk.NULL_PIPELINE, false
304 350 }
305 - vs := &g_gl.shaders[desc.vert_shader]
306 - fs := &g_gl.shaders[desc.frag_shader]
307 - if !vs.active || !fs.active {
351 + vs, vs_ok := shader_entry(desc.vert_shader)
352 + fs, fs_ok := shader_entry(desc.frag_shader)
353 + if !vs_ok || !fs_ok {
308 354 log.error("gpu/opengl: graphics pipeline shader handle is invalid")
309 355 return bk.NULL_PIPELINE, false
310 356 }
42 unchanged lines hidden
353 399 }
354 400
355 401 destroy_graphics_pipeline_opengl :: proc(handle: bk.Pipeline_Handle) {
356 - if handle == bk.NULL_PIPELINE do return
357 - entry := &g_gl.pipelines[handle]
358 - if !entry.active do return
402 + entry, ok := pipeline_entry(handle)
403 + if !ok do return
359 404 if entry.vao != 0 {
360 405 id := entry.vao
361 406 gl.DeleteVertexArrays(1, &id)
3 unchanged lines hidden
365 410 }
366 411
367 412 bind_graphics_pipeline_opengl :: proc(ctx: bk.Frame_Context, handle: bk.Pipeline_Handle) {
368 - if handle == bk.NULL_PIPELINE do return
369 - entry := &g_gl.pipelines[handle]
370 - if !entry.active do return
413 + entry, ok := pipeline_entry(handle)
414 + if !ok do return
371 415 g_gl.current_pipeline = handle
372 416 gl.UseProgram(entry.program)
373 417 gl.BindVertexArray(entry.vao)
2 unchanged lines hidden
376 420
377 421 create_compute_pipeline_opengl :: proc(shader: bk.Shader_Handle, num_buffers: u32, push_constant_size: u32) -> (bk.Pipeline_Handle, bool) {
378 422 if shader == bk.NULL_SHADER do return bk.NULL_PIPELINE, false
379 - cs := &g_gl.shaders[shader]
380 - if !cs.active || cs.stage != .Compute {
423 + cs, cs_ok := shader_entry(shader)
424 + if !cs_ok || cs.stage != .Compute {
381 425 log.error("gpu/opengl: compute pipeline requires compute shader")
382 426 return bk.NULL_PIPELINE, false
383 427 }
18 unchanged lines hidden
402 446 }
403 447
404 448 bind_compute_pipeline_opengl :: proc(ctx: bk.Frame_Context, handle: bk.Pipeline_Handle) {
405 - if handle == bk.NULL_PIPELINE do return
406 - entry := &g_gl.pipelines[handle]
407 - if !entry.active || !entry.is_compute do return
449 + entry, ok := pipeline_entry(handle)
450 + if !ok || !entry.is_compute do return
408 451 g_gl.current_pipeline = handle
409 452 gl.UseProgram(entry.program)
410 453 }
24 unchanged lines hidden
435 478 }
436 479
437 480 destroy_descriptor_set_layout_opengl :: proc(handle: bk.Descriptor_Handle) {
438 - if handle == bk.NULL_DESCRIPTOR do return
439 - g_gl.descriptors[handle] = {}
481 + entry, ok := descriptor_entry_of_kind(handle, .Set_Layout)
482 + if !ok do return
483 + entry^ = {}
440 484 }
441 485
442 486 create_descriptor_pool_opengl :: proc(max_sets: u32, types: []bk.Descriptor_Type, counts: []u32) -> (bk.Descriptor_Handle, bool) {
6 unchanged lines hidden
449 493 }
450 494
451 495 destroy_descriptor_pool_opengl :: proc(handle: bk.Descriptor_Handle) {
452 - if handle == bk.NULL_DESCRIPTOR do return
453 - g_gl.descriptors[handle] = {}
496 + entry, ok := descriptor_entry_of_kind(handle, .Pool)
497 + if !ok do return
498 + entry^ = {}
454 499 }
455 500
456 501 allocate_descriptor_set_opengl :: proc(pool: bk.Descriptor_Handle, layout: bk.Descriptor_Handle) -> (bk.Descriptor_Handle, bool) {
457 502 if pool == bk.NULL_DESCRIPTOR || layout == bk.NULL_DESCRIPTOR do return bk.NULL_DESCRIPTOR, false
458 - layout_entry := &g_gl.descriptors[layout]
459 - if !layout_entry.active || layout_entry.kind != .Set_Layout do return bk.NULL_DESCRIPTOR, false
503 + if _, pool_ok := descriptor_entry_of_kind(pool, .Pool); !pool_ok do return bk.NULL_DESCRIPTOR, false
504 + layout_entry, layout_ok := descriptor_entry_of_kind(layout, .Set_Layout)
505 + if !layout_ok do return bk.NULL_DESCRIPTOR, false
460 506 handle, ok := alloc_descriptor_handle()
461 507 if !ok do return bk.NULL_DESCRIPTOR, false
462 508 entry := &g_gl.descriptors[handle]
11 unchanged lines hidden
474 520 }
475 521
476 522 bind_descriptor_set_opengl :: proc(ctx: bk.Frame_Context, pipeline: bk.Pipeline_Handle, set: bk.Descriptor_Handle, index: u32) {
477 - if set == bk.NULL_DESCRIPTOR do return
478 - entry := &g_gl.descriptors[set]
479 - if !entry.active || entry.kind != .Set do return
523 + entry, ok := descriptor_entry_of_kind(set, .Set)
524 + if !ok do return
480 525 for i in 0..<int(entry.binding_count) {
481 526 b := entry.bindings[i]
482 527 point := descriptor_binding_point(index, b.binding)
483 528 switch b.type {
484 529 case .Combined_Image_Sampler:
485 530 if b.texture != bk.NULL_TEXTURE {
486 - tex := &g_gl.textures[b.texture]
487 - if tex.active do gl.BindTextureUnit(point, tex.id)
531 + if tex, tex_ok := texture_entry(b.texture); tex_ok do gl.BindTextureUnit(point, tex.id)
488 532 }
489 533 if b.sampler != bk.NULL_SAMPLER {
490 - samp := &g_gl.samplers[b.sampler]
491 - if samp.active do gl.BindSampler(point, samp.id)
534 + if samp, samp_ok := sampler_entry(b.sampler); samp_ok do gl.BindSampler(point, samp.id)
492 535 }
493 536 case .Uniform_Buffer:
494 537 if point == OPENGL_PUSH_CONSTANT_BINDING {
1 unchanged lines hidden
496 539 continue
497 540 }
498 541 if b.buffer != bk.NULL_BUFFER {
499 - buf := &g_gl.buffers[b.buffer]
500 - if buf.active do gl.BindBufferBase(gl.UNIFORM_BUFFER, point, buf.id)
542 + if buf, buf_ok := buffer_entry(b.buffer); buf_ok do gl.BindBufferBase(gl.UNIFORM_BUFFER, point, buf.id)
501 543 }
502 544 case .Storage_Buffer:
503 545 if b.buffer != bk.NULL_BUFFER {
504 - buf := &g_gl.buffers[b.buffer]
505 - if buf.active do gl.BindBufferBase(gl.SHADER_STORAGE_BUFFER, point, buf.id)
546 + if buf, buf_ok := buffer_entry(b.buffer); buf_ok do gl.BindBufferBase(gl.SHADER_STORAGE_BUFFER, point, buf.id)
506 547 }
507 548 }
508 549 }
509 550 }
510 551
511 552 update_descriptor_image_opengl :: proc(set: bk.Descriptor_Handle, binding: u32, texture: bk.Texture_Handle, sampler: bk.Sampler_Handle, layout: bk.Image_Layout) {
512 - if set == bk.NULL_DESCRIPTOR do return
513 - entry := &g_gl.descriptors[set]
514 - if !entry.active || entry.kind != .Set do return
553 + entry, ok := descriptor_entry_of_kind(set, .Set)
554 + if !ok do return
515 555 for i in 0..<int(entry.binding_count) {
516 556 if entry.bindings[i].binding == binding {
517 557 entry.bindings[i].texture = texture
4 unchanged lines hidden
522 562 }
523 563
524 564 update_descriptor_buffer_opengl :: proc(set: bk.Descriptor_Handle, binding: u32, buffer: bk.Buffer_Handle, size: u64) {
525 - if set == bk.NULL_DESCRIPTOR do return
526 - entry := &g_gl.descriptors[set]
527 - if !entry.active || entry.kind != .Set do return
565 + entry, ok := descriptor_entry_of_kind(set, .Set)
566 + if !ok do return
528 567 for i in 0..<int(entry.binding_count) {
529 568 if entry.bindings[i].binding == binding {
530 569 entry.bindings[i].buffer = buffer
14 unchanged lines hidden
545 584
546 585 destroy_render_pass_opengl :: proc(handle: bk.Render_Pass_Handle) {
547 586 if handle == bk.NULL_RENDER_PASS || handle == g_gl.default_render_pass do return
548 - g_gl.render_passes[handle] = {}
587 + entry, ok := render_pass_entry(handle)
588 + if !ok do return
589 + entry^ = {}
549 590 }
550 591
551 592 create_framebuffer_opengl :: proc(desc: bk.Framebuffer_Desc) -> (bk.Framebuffer_Handle, bool) {
8 unchanged lines hidden
560 601 }
561 602
562 603 if desc.color_view != bk.NULL_TEXTURE {
563 - color := &g_gl.textures[desc.color_view]
564 - if !color.active {
604 + color, color_ok := texture_entry(desc.color_view)
605 + if !color_ok {
565 606 gl.DeleteFramebuffers(1, &id)
566 607 return bk.NULL_FRAMEBUFFER, false
567 608 }
2 unchanged lines hidden
570 611 gl.NamedFramebufferDrawBuffers(id, 1, &buf)
571 612 }
572 613 if desc.depth_view != bk.NULL_TEXTURE {
573 - depth := &g_gl.textures[desc.depth_view]
574 - if !depth.active {
614 + depth, depth_ok := texture_entry(desc.depth_view)
615 + if !depth_ok {
575 616 gl.DeleteFramebuffers(1, &id)
576 617 return bk.NULL_FRAMEBUFFER, false
577 618 }
18 unchanged lines hidden
596 637 }
597 638
598 639 destroy_framebuffer_opengl :: proc(handle: bk.Framebuffer_Handle) {
599 - if handle == bk.NULL_FRAMEBUFFER do return
600 - entry := &g_gl.framebuffers[handle]
601 - if !entry.active do return
640 + entry, ok := framebuffer_entry(handle)
641 + if !ok do return
602 642 if entry.id != 0 {
603 643 id := entry.id
604 644 gl.DeleteFramebuffers(1, &id)
3 unchanged lines hidden
608 648
609 649 draw_indexed_opengl :: proc(ctx: bk.Frame_Context, index_count, instance_count: u32, first_index: u32, vertex_offset: i32, first_instance: u32) {
610 650 if g_gl.current_pipeline == bk.NULL_PIPELINE do return
611 - pipeline := &g_gl.pipelines[g_gl.current_pipeline]
612 - if !pipeline.active do return
651 + pipeline, ok := pipeline_entry(g_gl.current_pipeline)
652 + if !ok do return
613 653 offset := rawptr(uintptr(first_index) * uintptr(size_of(u32)))
614 654 gl.DrawElementsInstancedBaseVertexBaseInstance(pipeline.topology, i32(index_count), gl.UNSIGNED_INT, offset, i32(instance_count), vertex_offset, first_instance)
615 655 }
77 unchanged lines hidden
gpu/tests/backend_handle_test.odin +30 -0 added
1 + package gpu_tests
2 +
3 + import "core:testing"
4 + import bk "../backend"
5 + import gl_backend "../backend/opengl"
6 +
7 + Test_Pool_Entry :: struct {
8 + active: bool,
9 + value: int,
10 + }
11 +
12 + @(test)
13 + test_opengl_active_pool_entry_validates_bounds_and_active_state :: proc(t: ^testing.T) {
14 + pool: [4]Test_Pool_Entry
15 + pool[1] = {active = true, value = 42}
16 + pool[2] = {active = false, value = 99}
17 +
18 + entry, valid_ok := gl_backend.active_pool_entry(&pool, bk.Buffer_Handle(1))
19 + testing.expect(t, valid_ok)
20 + testing.expect_value(t, entry.value, 42)
21 +
22 + _, null_ok := gl_backend.active_pool_entry(&pool, bk.NULL_BUFFER)
23 + testing.expect(t, !null_ok)
24 +
25 + _, inactive_ok := gl_backend.active_pool_entry(&pool, bk.Buffer_Handle(2))
26 + testing.expect(t, !inactive_ok)
27 +
28 + _, out_of_range_ok := gl_backend.active_pool_entry(&pool, bk.Buffer_Handle(4))
29 + testing.expect(t, !out_of_range_ok)
30 + }