Prevent mem leaks with destructors for all GPU objects and other measures.
This commit is contained in:
parent
52a4c00ffe
commit
8075edf619
|
@ -164,15 +164,15 @@ proc set_attachments(self: Framebuffer; layer, mipmap_level: int) =
|
|||
if tex.tex_type == Tex2DArray:
|
||||
assert layer >= 0, "Texture array layer must be specified"
|
||||
glFramebufferTextureLayer(GL_FRAMEBUFFER, attachments[i],
|
||||
tex.storage.tex, mipmap_level.GLint, layer.GLint)
|
||||
tex.storage.tex.GLuint, mipmap_level.GLint, layer.GLint)
|
||||
elif tex.tex_type == TexCube:
|
||||
assert layer >= 0, "Texture cube side must be specified"
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachments[i],
|
||||
(GL_TEXTURE_CUBE_MAP_POSITIVE_X.int + layer).GLenum,
|
||||
tex.storage.tex, mipmap_level.GLint)
|
||||
tex.storage.tex.GLuint, mipmap_level.GLint)
|
||||
elif self.current_mipmap_level != mipmap_level:
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachments[i],
|
||||
tex.storage.target, tex.storage.tex, mipmap_level.GLint)
|
||||
tex.storage.target, tex.storage.tex.GLuint, mipmap_level.GLint)
|
||||
|
||||
proc enable*(self: Framebuffer, rect = none((int32,int32,int32,int32)),
|
||||
layer = -1, mipmap_level = 0, mark_textures = true): Framebuffer {.discardable.} =
|
||||
|
|
|
@ -186,8 +186,8 @@ proc delete_all_shaders*(self: Material, destroy: bool = true) =
|
|||
self.last_shader = nil
|
||||
|
||||
proc destroy*(self: Material) =
|
||||
for shader in values(self.shaders):
|
||||
shader.destroy()
|
||||
self.delete_all_shaders()
|
||||
self.textures.clear()
|
||||
|
||||
var id = 0
|
||||
|
||||
|
@ -389,12 +389,14 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
when not defined(release):
|
||||
self.vs_code = vs
|
||||
let vertex_shader = glCreateShader(GL_VERTEX_SHADER)
|
||||
defer: glDeleteShader(vertex_shader)
|
||||
# TODO: make a pointer array from the unjoined strings, interleaved with "\n"
|
||||
# instead of concatenating and converting
|
||||
var vs2 = vs.cstring
|
||||
glShaderSource(vertex_shader, 1, cast[cstringArray](addr vs2), nil)
|
||||
glCompileShader(vertex_shader)
|
||||
var fragment_shader: GLuint = 0
|
||||
defer: glDeleteShader(fragment_shader)
|
||||
template fragment:string = fragment_lines.join("\n")
|
||||
if has_fragment_shader:
|
||||
fragment_shader = glCreateShader(GL_FRAGMENT_SHADER)
|
||||
|
@ -404,6 +406,10 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
glShaderSource(fragment_shader, 1, cast[cstringArray](addr fragment2), nil)
|
||||
glCompileShader(fragment_shader)
|
||||
let prog = glCreateProgram()
|
||||
defer:
|
||||
if prog != self.program.GLuint:
|
||||
echo "deleting program"
|
||||
glDeleteProgram(prog)
|
||||
glAttachShader(prog, vertex_shader)
|
||||
if fragment_shader != 0:
|
||||
glAttachShader(prog, fragment_shader)
|
||||
|
@ -425,7 +431,6 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
echo vs.add_line_numbers(1)
|
||||
let error_msg = dedent &"""Error compiling vertex shader of material {material.name}
|
||||
{get_shader_info_log(vertex_shader)}"""
|
||||
glDeleteShader(vertex_shader)
|
||||
console_error(error_msg)
|
||||
return
|
||||
if fragment_shader != 0:
|
||||
|
@ -435,7 +440,6 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
let error_msg = &"Error compiling fragment shader of material {material.name}\n{gl_log}"
|
||||
# console_error fragment
|
||||
let lines = fragment.split("\n")
|
||||
glDeleteShader(fragment_shader)
|
||||
if "ERROR: 0:" in gl_log:
|
||||
# Show engine for first error
|
||||
let line = try: error_msg.split(":")[2].parseInt except: 0
|
||||
|
@ -463,9 +467,6 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
# console_error fragment
|
||||
console_error("================")
|
||||
console_error error_msg
|
||||
glDeleteProgram(prog)
|
||||
glDeleteShader(vertex_shader)
|
||||
glDeleteShader(fragment_shader)
|
||||
return
|
||||
|
||||
self.camera_render_ubo_index = glGetUniformBlockIndex(prog, "CameraRenderUniform")
|
||||
|
@ -517,12 +518,13 @@ proc initShader*(self: Shader, engine: MyouEngine, material: Material,
|
|||
assert self.texture_locations.len + self.cubemap_locations.len +
|
||||
extra_location_count <= self.engine.renderer.max_textures
|
||||
|
||||
self.program = prog
|
||||
self.program = prog.GPUProgram
|
||||
|
||||
proc use*(self: Shader): GLuint {.inline,discardable.} =
|
||||
glUseProgram(self.program)
|
||||
return self.program
|
||||
glUseProgram(self.program.GLuint)
|
||||
return self.program.GLuint
|
||||
|
||||
proc destroy*(self: Shader) =
|
||||
glDeleteProgram(self.program)
|
||||
self.program = 0.GPUProgram
|
||||
|
||||
|
||||
|
|
|
@ -255,23 +255,22 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
# TODO: Also check with cam_data.clipping_plane!
|
||||
|
||||
# TODO: Select alternative mesh / LoD
|
||||
var amesh = mesh
|
||||
var amesh {.cursor.} = mesh
|
||||
if not (amesh.data != nil and amesh.data.loaded):
|
||||
return
|
||||
self.set_flip_normals mesh.flip
|
||||
let data = amesh.data
|
||||
|
||||
# for ubo in self.bound_ubos:
|
||||
# if ubo != nil:
|
||||
# ubo.unbind()
|
||||
# self.next_ubo = 0
|
||||
let data {.cursor.} = amesh.data
|
||||
|
||||
# unbindAllTextures()
|
||||
|
||||
# Main routine for each submesh
|
||||
# (vao may be null but that's handled later)
|
||||
for submesh_idx, vao in data.vaos:
|
||||
if vao == 0:
|
||||
|
||||
# vaos have a destructor, and `pairs` copied the value,
|
||||
# so we either use `mpairs` or keep track of submesh_idx separately.
|
||||
var submesh_idx = -1
|
||||
for vao in data.vaos:
|
||||
submesh_idx.inc
|
||||
if vao.GLuint == 0.GLuint:
|
||||
continue
|
||||
|
||||
if not (pass == -1 or mesh.passes[submesh_idx] == pass):
|
||||
|
@ -282,10 +281,10 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
else:
|
||||
material_override
|
||||
|
||||
let shader = mat.get_shader(mesh)
|
||||
if shader.program == 0:
|
||||
let shader {.cursor.} = mat.get_shader(mesh)
|
||||
let program = shader.use()
|
||||
if program == 0:
|
||||
continue
|
||||
shader.use()
|
||||
self.set_cull_face(not mat.double_sided)
|
||||
|
||||
var ubos_to_bind: seq[UBO]
|
||||
|
@ -313,7 +312,7 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
# TODO: move this UBO, consolidate with cameradata
|
||||
# TODO: update only in draw_viewport
|
||||
if shader.camera_render_ubo_index.is_valid:
|
||||
let ubo = self.camera_render_ubo
|
||||
let ubo {.cursor.} = self.camera_render_ubo
|
||||
ubos_to_bind.add ubo
|
||||
ubo_indices.add shader.camera_render_ubo_index
|
||||
ubo.storage(CameraRenderUniform)[0] = CameraRenderUniform(
|
||||
|
@ -327,7 +326,7 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
ubos_to_update.add ubo
|
||||
|
||||
if shader.object_ubo_index.is_valid:
|
||||
let ubo = mesh.object_ubo
|
||||
let ubo {.cursor.} = mesh.object_ubo
|
||||
ubos_to_bind.add ubo
|
||||
ubo_indices.add shader.object_ubo_index
|
||||
const diag = vec3(1).normalize
|
||||
|
@ -344,13 +343,13 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
|
||||
# UBOs
|
||||
for i,idx in shader.ubo_indices:
|
||||
let ubo = shader.ubos[i]
|
||||
let ubo {.cursor.} = shader.ubos[i]
|
||||
ubos_to_bind.add ubo
|
||||
ubo_indices.add idx
|
||||
|
||||
ubos_to_bind.bind_all()
|
||||
for i,ubo in ubos_to_bind:
|
||||
ubo.set_prog_index(shader.program, ubo_indices[i])
|
||||
ubo.set_prog_index(program, ubo_indices[i])
|
||||
for ubo in ubos_to_update:
|
||||
ubo.update()
|
||||
|
||||
|
@ -364,8 +363,9 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
textures_to_bind.add texture
|
||||
else:
|
||||
textures_to_bind.add self.blank_texture
|
||||
assert texture_locations.len == textures_to_bind.len
|
||||
|
||||
let scene = mesh.scene
|
||||
let scene {.cursor.} = mesh.scene
|
||||
if scene != nil:
|
||||
let loc = shader.shadowmap_location
|
||||
let fb = scene.shadow_maps
|
||||
|
@ -389,9 +389,9 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
|
||||
bind_all(textures_to_bind, texture_locations)
|
||||
|
||||
let index_buffer = data.index_buffers[submesh_idx]
|
||||
let index_buffer = data.index_buffers[submesh_idx].GLuint
|
||||
let num_indices = data.num_indices[submesh_idx]
|
||||
glBindVertexArray(vao)
|
||||
glBindVertexArray(vao.GLuint)
|
||||
if not data.use_tf:
|
||||
if index_buffer != 0:
|
||||
glDrawElements(data.draw_method.GLenum, num_indices.GLsizei, data.index_types[submesh_idx].GLenum, cast[pointer](0))
|
||||
|
@ -399,7 +399,7 @@ proc draw_mesh*(self: RenderManager, mesh: Mesh, mesh2world: Mat4, cam_data: Ren
|
|||
glDrawArrays(data.draw_method.GLenum, 0, num_indices)
|
||||
else:
|
||||
assert index_buffer == 0, "Loopback transform feedback is not compatible with indexed meshes"
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, data.tf_vbos[1][submesh_idx])
|
||||
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, data.tf_vbos[1][submesh_idx].GLuint)
|
||||
glBeginTransformFeedback(data.draw_method.GLenum)
|
||||
glDrawArrays(data.draw_method.GLenum, 0, num_indices)
|
||||
glEndTransformFeedback()
|
||||
|
|
|
@ -194,11 +194,13 @@ proc newTextureStorage*(ttype: TextureType, width, height, depth: int, format: T
|
|||
# of Depth_u24_s8: GL_UNSIGNED_INT
|
||||
ts.layer = 0
|
||||
ts.tile_size = vec2(1,1)
|
||||
glGenTextures(1, addr ts.tex)
|
||||
var tex: GLuint
|
||||
glGenTextures(1, addr tex)
|
||||
ts.tex = tex.GPUTexture
|
||||
return ts
|
||||
|
||||
proc preallocate(self: Texture) =
|
||||
let ts = self.storage
|
||||
let ts {.cursor.} = self.storage
|
||||
case self.tex_type:
|
||||
of Tex2D:
|
||||
# TODO: only do this if necessary
|
||||
|
@ -232,9 +234,7 @@ proc preallocate(self: Texture) =
|
|||
discard
|
||||
|
||||
proc freeTextureStorage(self: Texture) =
|
||||
if self.storage != nil:
|
||||
glDeleteTextures(1, addr self.storage.tex)
|
||||
self.storage = nil
|
||||
self.storage = nil
|
||||
|
||||
proc bind_it*(texture: Texture, reserve_slot: static[int32] = -1, needs_active_texture: static[bool] = false) =
|
||||
# TODO: rewrite for using texture arrays and/or bindless
|
||||
|
@ -252,7 +252,7 @@ proc bind_it*(texture: Texture, reserve_slot: static[int32] = -1, needs_active_t
|
|||
if active_texture != bound_unit:
|
||||
active_texture = bound_unit
|
||||
glActiveTexture(cast[GLenum](GL_TEXTURE0.uint32 + bound_unit.uint32))
|
||||
var old_tex = bound_textures[bound_unit]
|
||||
var old_tex {.cursor.} = bound_textures[bound_unit]
|
||||
if old_tex != nil:
|
||||
old_tex.storage.unit = -1
|
||||
if old_tex.storage.target.uint32 != texture.storage.target.uint32:
|
||||
|
@ -260,7 +260,7 @@ proc bind_it*(texture: Texture, reserve_slot: static[int32] = -1, needs_active_t
|
|||
# if old_tex.sampler_object != 0:
|
||||
# glBindSampler(cast[GLuint](bound_unit), 0)
|
||||
bound_textures[bound_unit] = nil
|
||||
glBindTexture(texture.storage.target, texture.storage.tex)
|
||||
glBindTexture(texture.storage.target, texture.storage.tex.GLuint)
|
||||
# if texture.sampler_object != 0:
|
||||
# glBindSampler(bound_unit.GLuint, texture.sampler_object)
|
||||
bound_textures[bound_unit] = texture
|
||||
|
@ -277,7 +277,7 @@ proc unbind*(texture: Texture) =
|
|||
if texture.storage.unit == -1:
|
||||
return
|
||||
let bound_unit = texture.storage.unit
|
||||
var old_tex = bound_textures[bound_unit]
|
||||
var old_tex {.cursor.} = bound_textures[bound_unit]
|
||||
assert old_tex == texture, "unexpected bound texture"
|
||||
if old_tex == texture:
|
||||
bound_textures[bound_unit] = nil
|
||||
|
@ -308,19 +308,17 @@ proc bind_all*(textures: seq[Texture], locations: seq[GLint]) =
|
|||
active_texture = unit
|
||||
texture.storage.unit = unit
|
||||
glActiveTexture(cast[GLenum](GL_TEXTURE0.uint32 + unit.uint32))
|
||||
let old_tex = bound_textures[unit]
|
||||
let old_tex {.cursor.} = bound_textures[unit]
|
||||
if old_tex != nil:
|
||||
old_tex.storage.unit = -1
|
||||
if old_tex.storage.target != texture.storage.target:
|
||||
glBindTexture(old_tex.storage.target, 0)
|
||||
glBindTexture(texture.storage.target, texture.storage.tex)
|
||||
glBindTexture(texture.storage.target, texture.storage.tex.GLuint)
|
||||
bound_textures[unit] = texture
|
||||
inc(next_texture)
|
||||
if next_texture == max_textures:
|
||||
next_texture = 0
|
||||
glUniform1i(locations[i], unit)
|
||||
|
||||
|
||||
|
||||
proc unbindAllTextures*() =
|
||||
for tex in bound_textures:
|
||||
|
@ -428,7 +426,7 @@ proc newTexture*(engine: MyouEngine, name: string,
|
|||
when defined(myouUseRenderdoc):
|
||||
# Note: when we switch to arrays we'll have to store resolutions
|
||||
# instead of names
|
||||
glObjectLabel(GL_TEXTURE, self.storage.tex,
|
||||
glObjectLabel(GL_TEXTURE, self.storage.tex.GLuint,
|
||||
GLsizei(self.name.len), self.name.cstring)
|
||||
|
||||
proc generateMipmap*(self: Texture) =
|
||||
|
|
|
@ -61,12 +61,14 @@ proc initUBO*[T](self: UBO, renderer: RenderManager, name: string, utype: typede
|
|||
self.binding_point = -1
|
||||
|
||||
renderer.enqueue proc() =
|
||||
glGenBuffers 1, addr self.buffer
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, self.buffer)
|
||||
var buffer: GLuint
|
||||
glGenBuffers 1, addr buffer
|
||||
self.buffer = GPUBuffer(buffer)
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, buffer)
|
||||
glBufferData(GL_UNIFORM_BUFFER, cast[GLsizeiptr](self.byte_storage.byte_len), nil, GL_DYNAMIC_DRAW)
|
||||
# glBindBuffer(GL_UNIFORM_BUFFER, 0)
|
||||
when defined(myouUseRenderdoc):
|
||||
glObjectLabel(GL_BUFFER, self.buffer, GLsizei(name.len), name.cstring)
|
||||
glObjectLabel(GL_BUFFER, buffer, GLsizei(name.len), name.cstring)
|
||||
return self
|
||||
|
||||
template storage*[T](self: UBO, utype: typedesc[T]): ArrRef[T] = self.byte_storage.to(T)
|
||||
|
@ -83,16 +85,17 @@ proc resize*[T](self: UBO, utype: typedesc[T], count: int) =
|
|||
# but I'm deleting and unbinding the buffer just in case
|
||||
self.unbind()
|
||||
self.byte_storage = newArrRef[T](count).to(byte)
|
||||
glDeleteBuffers 1, addr self.buffer
|
||||
glGenBuffers 1, addr self.buffer
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, self.buffer)
|
||||
var buffer: GLuint
|
||||
glGenBuffers 1, addr buffer
|
||||
self.buffer = GPUBuffer(buffer)
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, buffer)
|
||||
# TODO: set nil instead of the actual buffer,
|
||||
# and avoid using it until it's updated for the first time
|
||||
glBufferData(GL_UNIFORM_BUFFER, cast[GLsizeiptr](self.byte_storage.len), self.byte_storage.toPointer, GL_DYNAMIC_DRAW)
|
||||
# glBindBuffer(GL_UNIFORM_BUFFER, 0)
|
||||
when defined(myouUseRenderdoc):
|
||||
let name = self.name & "*" # asterisk = it was resized
|
||||
glObjectLabel(GL_BUFFER, self.buffer, GLsizei(name.len), name.cstring)
|
||||
glObjectLabel(GL_BUFFER, buffer, GLsizei(name.len), name.cstring)
|
||||
|
||||
proc newUBO*[T](renderer: RenderManager, name: string, utype: typedesc[T], count: int = 1): UBO =
|
||||
var ubo = new UBO
|
||||
|
@ -126,9 +129,9 @@ proc bind_it*(self: UBO, rebind = false) =
|
|||
if next_ubo == self.renderer.max_uniform_buffer_bindings:
|
||||
next_ubo = 0
|
||||
self.renderer.next_ubo = next_ubo
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.binding_point.GLuint, self.buffer)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.binding_point.GLuint, self.buffer.GLuint)
|
||||
elif rebind:
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.binding_point.GLuint, self.buffer)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, self.binding_point.GLuint, self.buffer.GLuint)
|
||||
|
||||
proc unbind*(self: UBO) =
|
||||
if self.binding_point != -1:
|
||||
|
@ -158,7 +161,7 @@ proc bind_all*(ubos: seq[UBO]) =
|
|||
old_ubo.binding_point = -1
|
||||
renderer.bound_ubos[next_ubo] = ubo
|
||||
ubo.binding_point = next_ubo
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, next_ubo.GLuint, ubo.buffer)
|
||||
glBindBufferBase(GL_UNIFORM_BUFFER, next_ubo.GLuint, ubo.buffer.GLuint)
|
||||
inc(next_ubo)
|
||||
if next_ubo == maxubos:
|
||||
next_ubo = 0
|
||||
|
@ -179,7 +182,7 @@ proc update*(self: UBO) {.inline.} =
|
|||
# NOTE: if this doesn't work in webgl, set a flag
|
||||
let len = self.byte_storage.len
|
||||
if len != 0:
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, self.buffer)
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, self.buffer.GLuint)
|
||||
glBufferData(GL_UNIFORM_BUFFER, len.GLsizeiptr, self.byte_storage.toPointer, GL_DYNAMIC_DRAW)
|
||||
# glBindBuffer(GL_UNIFORM_BUFFER, 0)
|
||||
|
||||
|
@ -189,7 +192,7 @@ template is_valid*(block_index: GLuint): bool =
|
|||
proc destroy*(self: UBO) =
|
||||
self.unbind()
|
||||
self.byte_storage = nil
|
||||
glDeleteBuffers 1, addr self.buffer
|
||||
self.buffer = 0.GPUBuffer
|
||||
|
||||
# TODO: make a function/template/macro that generates GLSL code to declare the UBO from an object
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ proc loadAsync(self: BlendLoader, callback: proc()) =
|
|||
self.close()
|
||||
self.resource = loadUri(self.blend_file_path,
|
||||
proc(ok, err, data: auto) =
|
||||
self.resource = nil
|
||||
if ok:
|
||||
self.blend_file = openBlendFile(self.blend_file_path, data.data, data.byte_len)
|
||||
callback()
|
||||
|
|
|
@ -87,11 +87,10 @@ type
|
|||
TypeLengths = ptr UncheckedArray[uint16]
|
||||
|
||||
FNode* = object
|
||||
dna: TypeAttrsRef
|
||||
blocks: FNodesByAddress
|
||||
blend_file {.cursor.}: BlendFile
|
||||
# we have to keep a reference to this otherwise it will be GC'd
|
||||
# TODO: remove the two pointers above to use less memory?
|
||||
blend_file: BlendFile
|
||||
# (but only in FNodes not referenced in the original, to avoid cycles)
|
||||
blend_file_ref: BlendFile
|
||||
|
||||
p: pointer
|
||||
count: uint32
|
||||
|
@ -285,8 +284,6 @@ proc openBlendFile*(path: string, data: pointer, len: int): BlendFile =
|
|||
p: blk.data.addr,
|
||||
tid: tid,
|
||||
count: if blk.count == 1: real_count else: blk.count,
|
||||
dna: type_attrs,
|
||||
blocks: node_blocks,
|
||||
blend_file: result)
|
||||
node_blocks[address] = node
|
||||
if blk.code[2] == '\0':
|
||||
|
@ -294,6 +291,7 @@ proc openBlendFile*(path: string, data: pointer, len: int): BlendFile =
|
|||
if t notin result.named_blocks:
|
||||
result.named_blocks[t] = @[]
|
||||
result.named_blocks[t].add(node)
|
||||
result.dna = type_attrs
|
||||
result.blocks = node_blocks
|
||||
result.type_names = type_names
|
||||
result.struct_to_type = struct_to_type
|
||||
|
@ -375,25 +373,25 @@ template get_fblock_of_node(n: FNode): ptr FBlock64 =
|
|||
proc contains*(n: FNode, name: string): bool =
|
||||
if n.p == nil:
|
||||
return
|
||||
return name in n.dna[n.tid]
|
||||
return name in n.blend_file.dna[n.tid]
|
||||
|
||||
proc `[]`*(n: FNode, name: string): FNode =
|
||||
if n.p == nil:
|
||||
return
|
||||
assert not n.count.testBit(31), "This is an array, expected index instead of \"" & name & "\""
|
||||
let a = n.dna[n.tid][name]
|
||||
let a = n.blend_file.dna[n.tid][name]
|
||||
if a.atype != Value:
|
||||
let ptri = cast[ptr uint64](n.p+a.offset)[]
|
||||
if ptri == 0:
|
||||
return
|
||||
when defined(disallow_missing_blocks):
|
||||
assert ptri in n.blocks, "Missing block pointing to: " & name
|
||||
if ptri notin n.blocks:
|
||||
assert ptri in n.blend_file.blocks, "Missing block pointing to: " & name
|
||||
if ptri notin n.blend_file.blocks:
|
||||
# This may happen if e.g. the user has deleted an image used by a node
|
||||
# so we'll just return an invalid node
|
||||
echo "Missing block pointing to: " & name
|
||||
return
|
||||
let blk = n.blocks[ptri]
|
||||
let blk = n.blend_file.blocks[ptri]
|
||||
var count: uint32 = a.count
|
||||
if a.atype == PointerArray:
|
||||
# the sdna_index of this block is 0, which would give an incorrect struct size
|
||||
|
@ -403,13 +401,15 @@ proc `[]`*(n: FNode, name: string): FNode =
|
|||
count.setBit 31
|
||||
# use blk.count?
|
||||
var node = FNode(p: blk.p, tid: a.tid, count: count,
|
||||
dna: n.dna, blocks: n.blocks, blend_file: n.blend_file)
|
||||
blend_file: n.blend_file,
|
||||
blend_file_ref: n.blend_file)
|
||||
if a.tid == B_void.uint16:
|
||||
node.tid = n.blend_file.struct_to_type[get_fblock_of_node(node).sdna_index]
|
||||
return node
|
||||
else:
|
||||
return FNode(p: n.p+a.offset, tid: a.tid, count: a.count,
|
||||
dna: n.dna, blocks: n.blocks, blend_file: n.blend_file)
|
||||
blend_file: n.blend_file,
|
||||
blend_file_ref: n.blend_file)
|
||||
|
||||
proc `[]`*(n: FNode, index: Natural): FNode =
|
||||
var count = n.count
|
||||
|
@ -419,16 +419,17 @@ proc `[]`*(n: FNode, index: Natural): FNode =
|
|||
let ptri = cast[ptr UncheckedArray[uint64]](n.p)[index]
|
||||
if ptri == 0:
|
||||
return
|
||||
assert ptri in n.blocks, "Missing block"
|
||||
let blk = n.blocks[ptri]
|
||||
assert ptri in n.blend_file.blocks, "Missing block"
|
||||
let blk = n.blend_file.blocks[ptri]
|
||||
return FNode(p: blk.p, tid: n.tid, count: 1,
|
||||
dna: n.dna, blocks: n.blocks, blend_file: n.blend_file)
|
||||
blend_file: n.blend_file,
|
||||
blend_file_ref: n.blend_file)
|
||||
else:
|
||||
var n = n
|
||||
let size = if n.tid < BASIC_TYPE_LENGTHS.len:
|
||||
BASIC_TYPE_LENGTHS[n.tid]
|
||||
else:
|
||||
# n.dna[n.tid]["(size)"].offset.int
|
||||
# n.blend_file.dna[n.tid]["(size)"].offset.int
|
||||
n.blend_file.type_lengths[n.tid].int
|
||||
n.p = n.p + index * size
|
||||
n.count = 1
|
||||
|
@ -444,10 +445,9 @@ iterator items*(n: FNode, stride=0): FNode =
|
|||
if ptri == 0:
|
||||
yield FNode()
|
||||
continue
|
||||
assert ptri in n.blocks, "Missing block"
|
||||
let blk = n.blocks[ptri]
|
||||
yield FNode(p: blk.p, tid: n.tid, count: 1,
|
||||
dna: n.dna, blocks: n.blocks)
|
||||
assert ptri in n.blend_file.blocks, "Missing block"
|
||||
let blk = n.blend_file.blocks[ptri]
|
||||
yield FNode(p: blk.p, tid: n.tid, count: 1)
|
||||
else:
|
||||
var n = n
|
||||
let stride = if stride == 0:
|
||||
|
@ -538,7 +538,7 @@ proc `$`*(n: FNode, depth=0, max_depth=3, just_name=false, dump_pointers=false):
|
|||
let kkstr = `$`(kk, depth, max_depth)
|
||||
ret.add indent & "[" & $i & "]: " & kkstr
|
||||
return ret.join "\n"
|
||||
var attrs = toSeq(n.dna[n.tid].pairs)
|
||||
var attrs = toSeq(n.blend_file.dna[n.tid].pairs)
|
||||
try:
|
||||
let name = n.id.name.str
|
||||
ret.add indent & "id.name: " & name
|
||||
|
|
|
@ -168,7 +168,6 @@ proc myou_main_loop*(self: MyouEngine) =
|
|||
##
|
||||
## You usually don't need to call this. Use `run <#run,MyouEngine>`_
|
||||
## instead.
|
||||
self.renderer.unbind_all_ubos()
|
||||
when compileOption("threads"):
|
||||
updateTextureWorkerThreads()
|
||||
updateLoadableWorkerThreads()
|
||||
|
|
|
@ -486,6 +486,9 @@ proc remove*(self: GameObject, recursive: bool = true) =
|
|||
self.scene.remove_object(self, recursive)
|
||||
|
||||
proc destroy*(self: GameObject, recursive: bool = true) =
|
||||
if self.is_mesh and self.get_mesh.data.nonNil:
|
||||
self.get_mesh.data.gpu_buffers_delete()
|
||||
self.get_mesh.materials.setLen 0
|
||||
self.body.destroy()
|
||||
self.remove(recursive)
|
||||
if recursive:
|
||||
|
@ -494,7 +497,9 @@ proc destroy*(self: GameObject, recursive: bool = true) =
|
|||
child.destroy(true)
|
||||
self.engine.objects.del(self.name)
|
||||
self.object_render_ubo.unbind()
|
||||
self.object_render_ubo.destroy()
|
||||
self.object_ubo.unbind()
|
||||
self.object_ubo.destroy()
|
||||
|
||||
proc convert_bone_child_to_bone_parent*(self: GameObject) =
|
||||
assert self.parent == nil or self.parent.is_armature, "An armature parent is required"
|
||||
|
|
|
@ -136,8 +136,6 @@ proc configure_shadow*(self: Light,
|
|||
for ob in self.scene.children:
|
||||
if not (ob.is_mesh and ob.visible):
|
||||
continue
|
||||
echo "adding ", ob.name, " otype ", ob.otype
|
||||
# discard ob.get_world_matrix
|
||||
let me = ob.get_mesh
|
||||
let bb = me.bound_box
|
||||
let world_dim = (ob.world_matrix * vec4(bb[1] - bb[0], 0.0)).xyz
|
||||
|
|
|
@ -91,23 +91,14 @@ proc remove*(self: MeshData, ob: Mesh, delete_buffers: bool = true) =
|
|||
self.users.delete(idx)
|
||||
idx = self.users.find(ob)
|
||||
if self.users.len == 0:
|
||||
# if delete_buffers:
|
||||
# glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
# for buf in self.vertex_buffers:
|
||||
# glDeleteBuffers(1, addr buf)
|
||||
# for buf in self.index_buffers:
|
||||
# glDeleteBuffers(1, addr buf)
|
||||
# glBindVertexArray(0)
|
||||
# for vao in self.vaos:
|
||||
# glDeleteVertexArrays(1, addr vao)
|
||||
self.engine.mesh_datas.del(self.hash)
|
||||
ob.data = nil
|
||||
|
||||
proc write_vaos*(self: MeshData) =
|
||||
for i,vao in self.vaos:
|
||||
if vao == 0:
|
||||
if vao.int == 0:
|
||||
continue
|
||||
glBindVertexArray(vao)
|
||||
glBindVertexArray(vao.GLuint)
|
||||
for vb_attrs in self.vao_specs[i].vbs.mitems:
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vb_attrs.vb)
|
||||
for a in vb_attrs.attribs:
|
||||
|
@ -117,7 +108,7 @@ proc write_vaos*(self: MeshData) =
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.vao_specs[i].ib)
|
||||
when defined(myouUseRenderdoc):
|
||||
let name = &"{self.name} {i}"
|
||||
glObjectLabel(GL_VERTEX_ARRAY, vao, GLsizei(name.len), name.cstring)
|
||||
glObjectLabel(GL_VERTEX_ARRAY, vao.GLuint, GLsizei(name.len), name.cstring)
|
||||
glBindVertexArray(0)
|
||||
|
||||
proc gpu_buffers_upload*(self: MeshData) =
|
||||
|
@ -130,9 +121,9 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
for idx,va in self.varrays:
|
||||
if va.len == 0:
|
||||
self.num_indices.add(0)
|
||||
self.vertex_buffers.add(0)
|
||||
self.index_buffers.add(0)
|
||||
self.vaos.add(0)
|
||||
self.vertex_buffers.add(0.GPUBuffer)
|
||||
self.index_buffers.add(0.GPUBuffer)
|
||||
self.vaos.add(0.GPUVao)
|
||||
self.vao_specs.add VaoSpec()
|
||||
continue
|
||||
var vb: GLuint
|
||||
|
@ -143,7 +134,7 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
# TODO: initialize without uploading when we know that the array is just zeroes
|
||||
glBufferData(GL_ARRAY_BUFFER, buffer_size.GLsizeiptr, addr va[0], GL_DYNAMIC_DRAW)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
self.vertex_buffers.add(vb)
|
||||
self.vertex_buffers.add(vb.GPUBuffer)
|
||||
var ib: GLuint = 0
|
||||
var num_indices: Natural
|
||||
if idx < self.iarrays.len:
|
||||
|
@ -167,7 +158,7 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
self.num_indices.add(num_indices.int32)
|
||||
elif not had_indices:
|
||||
self.num_indices.add((buffer_size div self.stride).int32)
|
||||
self.index_buffers.add(ib)
|
||||
self.index_buffers.add(ib.GPUBuffer)
|
||||
if self.use_tf:
|
||||
self.tf_vbos.setLen 2
|
||||
glGenBuffers(2, addr tf[0])
|
||||
|
@ -180,8 +171,8 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
glBindBuffer(GL_ARRAY_BUFFER, tf[1])
|
||||
glBufferData(GL_ARRAY_BUFFER, tf_buffer_size.GLsizeiptr, nil, GL_DYNAMIC_DRAW)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
self.tf_vbos[idx].add tf[0]
|
||||
self.tf_vbos[idx].add tf[1]
|
||||
self.tf_vbos[idx].add tf[0].GPUBuffer
|
||||
self.tf_vbos[idx].add tf[1].GPUBuffer
|
||||
# If transform feedback is enabled, we create two VAOs that have two
|
||||
# parts:
|
||||
# * The regular mesh, which has the same buffers and attributes in each
|
||||
|
@ -203,7 +194,7 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
)
|
||||
var vao: GLuint
|
||||
glGenVertexArrays(1, addr vao)
|
||||
self.vaos.add(vao)
|
||||
self.vaos.add(vao.GPUVao)
|
||||
if self.use_tf:
|
||||
var vao_tf = vao_spec
|
||||
vao_spec.vbs.add VertexBufferAttribs(vb: tf[0], attribs: self.tf_layout)
|
||||
|
@ -218,14 +209,15 @@ proc gpu_buffers_upload*(self: MeshData) =
|
|||
# set loaded to true after that
|
||||
|
||||
proc gpu_buffers_delete*(self: MeshData) =
|
||||
glBindVertexArray(0)
|
||||
self.vaos = @[]
|
||||
self.tf_vaos = @[]
|
||||
self.vao_specs = @[]
|
||||
self.tf_vao_specs = @[]
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0)
|
||||
self.vertex_buffers = @[]
|
||||
self.index_buffers = @[]
|
||||
self.loaded = false
|
||||
glBindVertexArray(0)
|
||||
for i in 0 ..< self.vaos.len:
|
||||
glDeleteVertexArrays(1, addr self.vaos[i])
|
||||
# TODO! delete individual buffers?
|
||||
self.vaos = @[]
|
||||
if self.users.len == 0:
|
||||
self.engine.mesh_datas.del(self.hash)
|
||||
|
||||
|
@ -233,14 +225,14 @@ proc update_varray*(self: MeshData) =
|
|||
if self.vertex_buffers.len == 0:
|
||||
return
|
||||
for i,va in self.varrays:
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffers[i])
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffers[i].GLuint)
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0.GLintptr, cast[GLsizeiptr](va.bytelen), addr va[0])
|
||||
|
||||
proc update_iarray*(self: MeshData) =
|
||||
if self.index_buffers.len == 0:
|
||||
return
|
||||
for i,ia in self.iarrays:
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buffers[i])
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.index_buffers[i].GLuint)
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, cast[GLsizeiptr](ia.bytelen), addr ia[0], GL_STATIC_DRAW)
|
||||
|
||||
proc clone*(self: MeshData): MeshData =
|
||||
|
|
|
@ -20,4 +20,49 @@ proc get_program_info_log*(program: GLuint): string =
|
|||
glGetProgramInfoLog(program, logSize.GLsizei, nil, s.cstring)
|
||||
return s
|
||||
|
||||
let main_thread_id = getThreadID()
|
||||
|
||||
template handleError(x: untyped, t: string) =
|
||||
assert main_thread_id == getThreadID()
|
||||
try:
|
||||
x
|
||||
except:
|
||||
echo "Error when deleting " & t
|
||||
echo getCurrentExceptionMsg()
|
||||
|
||||
type GPUBuffer* = distinct GLuint
|
||||
type GPUTexture* = distinct GLuint
|
||||
type GPUVao* = distinct GLuint
|
||||
type GPUFramebuffer* = distinct GLuint
|
||||
type GPURenderbuffer* = distinct GLuint
|
||||
type GPUProgram* = distinct GLuint
|
||||
type GPUShader* = distinct GLuint
|
||||
|
||||
proc `=destroy`(x: var GPUBuffer) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteBuffers(1, x.GLuint.addr), "Buffer"
|
||||
|
||||
proc `=destroy`(x: var GPUTexture) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteTextures(1, x.GLuint.addr), "Texture"
|
||||
|
||||
proc `=destroy`(x: var GPUVao) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteVertexArrays(1, x.GLuint.addr), "VertexArray"
|
||||
|
||||
proc `=destroy`(x: var GPUFramebuffer) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteFramebuffers(1, x.GLuint.addr), "Framebuffer"
|
||||
|
||||
proc `=destroy`(x: var GPURenderbuffer) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteRenderbuffers(1, x.GLuint.addr), "Renderbuffer"
|
||||
|
||||
proc `=destroy`(x: var GPUProgram) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteProgram(x.GLuint), "Program"
|
||||
|
||||
proc `=destroy`(x: var GPUShader) =
|
||||
if x.GLuint != 0.GLuint:
|
||||
handleError glDeleteShader(x.GLuint), "Shader"
|
||||
|
||||
|
|
|
@ -343,7 +343,6 @@ proc set_objects_auto_update_matrix*(self: Scene, objects: seq[GameObject], auto
|
|||
|
||||
proc destroy*(self: Scene) =
|
||||
for ob in reversed(self.children):
|
||||
var ob = ob
|
||||
ob.destroy(recursive=false)
|
||||
self.world.destroy()
|
||||
for mat in self.materials.values:
|
||||
|
@ -353,6 +352,17 @@ proc destroy*(self: Scene) =
|
|||
for ubo in self.lighting_UBOs:
|
||||
ubo.destroy()
|
||||
self.engine.scenes.del(self.name)
|
||||
# bound textures can linger
|
||||
unbindAllTextures()
|
||||
# probably none of this is actually necessary
|
||||
# (needs testing without this)
|
||||
self.children = @[]
|
||||
self.auto_updated_children = @[]
|
||||
self.objects.clear()
|
||||
self.parents.clear()
|
||||
self.materials.clear()
|
||||
self.textures.clear()
|
||||
self.mesh_passes = @[]
|
||||
|
||||
proc enable_render*(self: Scene) =
|
||||
self.enabled = true
|
||||
|
@ -417,9 +427,9 @@ proc calculate_max_lights_and_cubemaps*(self: Scene) =
|
|||
for _,mat in self.materials:
|
||||
if mat.ubos.anyIt it in self.lighting_UBOs:
|
||||
mat.delete_all_shaders
|
||||
echo &"calculated max lights {self.max_point_lights} {self.max_sun_lights}"
|
||||
echo &"calculated max shadow maps {self.max_shadow_maps}"
|
||||
echo &"calculated max cubemaps {self.max_cubemaps}"
|
||||
# echo &"calculated max lights {self.max_point_lights} {self.max_sun_lights}"
|
||||
# echo &"calculated max shadow maps {self.max_shadow_maps}"
|
||||
# echo &"calculated max cubemaps {self.max_cubemaps}"
|
||||
|
||||
proc get_lighting_UBOs*(self: Scene): seq[UBO] =
|
||||
# echo &"getting UBOs {self.max_point_lights} {self.max_sun_lights}"
|
||||
|
@ -620,7 +630,7 @@ proc sort_cubemaps*(self: Scene) =
|
|||
# or share depth buffers?
|
||||
|
||||
proc ensure_cubemaps*(self: Scene) =
|
||||
echo "ensuring cubemaps"
|
||||
# echo "ensuring cubemaps"
|
||||
let res = self.cubemap_resolution
|
||||
if res == 0:
|
||||
return
|
||||
|
@ -650,7 +660,7 @@ proc ensure_cubemaps*(self: Scene) =
|
|||
)
|
||||
probe.ubo_index = self.cubemaps.len.int32
|
||||
self.cubemaps.add(probe.cubemap)
|
||||
echo &"made {self.cubemaps.len} cubemaps"
|
||||
# echo &"made {self.cubemaps.len} cubemaps"
|
||||
|
||||
proc render_all_cubemaps*(self: Scene, use_roughness_prefiltering: bool, mipmap_shader: Material = nil) =
|
||||
if self.cubemap_UBO == nil:
|
||||
|
|
|
@ -167,11 +167,11 @@ type
|
|||
varrays*: seq[ArrRef[float32]]
|
||||
iarrays*: seq[ArrRef[uint16]]
|
||||
loaded*: bool
|
||||
vertex_buffers*: seq[GLuint] ## private
|
||||
vertex_buffers*: seq[GPUBuffer] ## private
|
||||
vertex_starts*: seq[int32] ## private
|
||||
index_buffers*: seq[GLuint] ## private
|
||||
index_buffers*: seq[GPUBuffer] ## private
|
||||
num_indices*: seq[int32] ## private
|
||||
vaos*: seq[GLuint] ## private
|
||||
vaos*: seq[GPUVao] ## private
|
||||
vao_specs*: seq[VaoSpec] ## private
|
||||
index_types*: seq[DataType] ## private
|
||||
layout*: AttributeList ## private
|
||||
|
@ -183,8 +183,8 @@ type
|
|||
# load_promise: unknown
|
||||
# load_resolve: unknown
|
||||
use_tf*: bool ## private
|
||||
tf_vbos*: seq[seq[GLuint]] ## private
|
||||
tf_vaos*: seq[GLuint] ## private
|
||||
tf_vbos*: seq[seq[GPUBuffer]] ## private
|
||||
tf_vaos*: seq[GPUVao] ## private
|
||||
tf_vao_specs*: seq[VaoSpec] ## private
|
||||
tf_layout*: AttributeList ## private
|
||||
when defined(myouUseRenderdoc):
|
||||
|
@ -504,7 +504,7 @@ type
|
|||
name*: string
|
||||
size32*: int
|
||||
byte_storage*: ArrRef[byte]
|
||||
buffer*: GLuint
|
||||
buffer*: GPUBuffer
|
||||
binding_point*: int32
|
||||
# needs_update*: bool
|
||||
|
||||
|
@ -555,14 +555,14 @@ type
|
|||
defines*: Table[string, string]
|
||||
|
||||
###
|
||||
scene*: Scene
|
||||
scene* {.cursor.}: Scene
|
||||
shaders*: Table[AttributeList, Shader] ## private
|
||||
users*: seq[GameObject] ## private
|
||||
render_scene*: Scene ## private
|
||||
render_scene* {.cursor.}: Scene ## private
|
||||
has_texture_list_checked*: bool ## private
|
||||
shader_library*: string ## private
|
||||
use_debug_shaders*: bool ## private
|
||||
last_shader*: Shader ## private
|
||||
last_shader* {.cursor.}: Shader ## private
|
||||
|
||||
feedback_varyings*: seq[string]
|
||||
|
||||
|
@ -570,8 +570,8 @@ type
|
|||
Shader* = ref object
|
||||
engine* {.cursor.}: MyouEngine # do we need this?
|
||||
id*: int
|
||||
program*: GLuint
|
||||
material*: Material # do we need this?
|
||||
program*: GPUProgram
|
||||
material* {.cursor.}: Material # do we need this?
|
||||
|
||||
# TODO: combine in single seq?
|
||||
ubos*: seq[UBO]
|
||||
|
@ -638,7 +638,7 @@ type
|
|||
TextureStorage* = ref object ## private
|
||||
unit*: GLint
|
||||
target*: GLenum
|
||||
tex*: GLuint
|
||||
tex*: GPUTexture
|
||||
iformat*: GLenum
|
||||
format*, gltype*: GLenum
|
||||
# index of the first layer (or only layer if not using tiles)
|
||||
|
@ -651,7 +651,7 @@ type
|
|||
name*: string
|
||||
storage*: TextureStorage ## private
|
||||
loaded*: bool
|
||||
last_used_shader*: Shader ## private
|
||||
last_used_shader* {.cursor.}: Shader ## private
|
||||
sampler_object*: GLuint ## private
|
||||
width*, height*, depth*: int
|
||||
tex_type*: TextureType
|
||||
|
@ -915,4 +915,5 @@ template enqueue*(renderer: RenderManager, fun: untyped) =
|
|||
|
||||
when not defined(release):
|
||||
from sugar import dump
|
||||
export sugar
|
||||
export sugar.dump
|
||||
|
||||
|
|
Loading…
Reference in a new issue