wip: uncommitted work gathered before the branch is merged into main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
cc384efee0
commit
737d6e1859
30 changed files with 307 additions and 120 deletions
|
|
@ -189,6 +189,9 @@ export state Render3dState {
|
|||
gvk_pool: long = 0
|
||||
gvk_fence: bytes = null
|
||||
gvk_frame_fence: bytes = null # the presented frame still on the GPU (one frame in flight)
|
||||
gvk_tmp_buf: pointer = null # the per-call scratch ring (gvk_tmp)
|
||||
gvk_tmp_off: int = 0
|
||||
gvk_seen: words = null # gvk_draw's vertex buffers already bound, reused
|
||||
gvk_frame_pending: bool = false
|
||||
gvk_frame_pending_cb: pointer = null
|
||||
gvk_frame_pending_no: int = -1 # which frame it is (gvk_frame_no when it was submitted)
|
||||
|
|
@ -197,6 +200,20 @@ export state Render3dState {
|
|||
gvk_retired_frame: []int = null # the last frame that read each retired buffer
|
||||
gvk_labels: bool = false # R3D_VK_LABELS: each profiled pass is a debug label (Metal System Trace)
|
||||
gvk_inflight: int = -1
|
||||
gvk_nopool: bool = false
|
||||
# R3D_VK_PROF: Vulkan objects made and destroyed, reported every 120 frames
|
||||
gvk_mk_img: int = 0
|
||||
gvk_mk_view: int = 0
|
||||
gvk_mk_buf: int = 0
|
||||
gvk_mk_mem: int = 0
|
||||
gvk_mk_smp: int = 0
|
||||
gvk_mk_set: int = 0
|
||||
gvk_mk_cmd: int = 0
|
||||
gvk_mk_dpool: int = 0
|
||||
gvk_mk_x_img: int = 0
|
||||
gvk_mk_x_view: int = 0
|
||||
gvk_mk_x_buf: int = 0
|
||||
gvk_mk_x_mem: int = 0
|
||||
gvk_label_depth: int = 0 # -1 until asked: 1 leaves the presented frame in flight
|
||||
gvk_has_hqr: bool = false
|
||||
gvk_ts_period: float = 0.0 # float bits: nanoseconds per timestamp tick
|
||||
|
|
@ -269,8 +286,9 @@ export state Render3dState {
|
|||
gvk_screen_depth: int = 0
|
||||
gvk_screen_w: int = 0
|
||||
gvk_screen_h: int = 0
|
||||
gvk_layer_views: []string = null # "tex:layer" -> index into gvk_layer_view
|
||||
gvk_layer_views: []int = null # generation * 4096 + layer, beside gvk_layer_view_tex
|
||||
gvk_layer_view: []long = null
|
||||
gvk_layer_view_tex: []int = null # the texture each cached view is of, so a release drops them
|
||||
gvk_fb_ncolor: words = null # per framebuffer: colour slots drawn (draw buffers; 0 = none)
|
||||
gvk_hdr_want: bool = false # r3d_hdr: the setting
|
||||
gvk_hdr_on: bool = false # the swapchain is HDR10 now
|
||||
|
|
@ -377,6 +395,11 @@ export state Render3dState {
|
|||
gg_mesh: []Mesh = null
|
||||
gg_n: int = 0
|
||||
gg_max: int = 0
|
||||
gg_rb: words = null # the per-frame dispatch arguments, made once (grass_gpu.ludic)
|
||||
gg_cb: words = null
|
||||
gg_bufs: words = null
|
||||
gg_texs: words = null
|
||||
gg_pr: words = null
|
||||
grass_band_mesh: []Mesh = null # per band: the blade it draws (rows fall with distance)
|
||||
grass_mesh3: Mesh = null # three rows: the middle distance
|
||||
grass_mesh2: Mesh = null # two rows, one quad: far enough that the arch is under a pixel
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ function gpu_query_new(render3d_st: mut Render3dState, n: int, ids: words) -> vo
|
|||
function gpu_query_begin(render3d_st: mut Render3dState, id: int) -> void { if render3d_st.gpu_kind == GPU_VK { gvk_query_begin(render3d_st, id); return }; gl_begin_query(GL_TIME_ELAPSED, id) }
|
||||
function gpu_query_end(render3d_st: mut Render3dState) -> void { if render3d_st.gpu_kind == GPU_VK { gvk_query_end(render3d_st); return }; gl_end_query(GL_TIME_ELAPSED) }
|
||||
# true once the query has its result; the nanoseconds (low 32 bits) are then in out[0]
|
||||
function gpu_query_result(render3d_st: Render3dState, id: int, out: words) -> bool {
|
||||
function gpu_query_result(render3d_st: mut Render3dState, id: int, out: words) -> bool {
|
||||
if render3d_st.gpu_kind == GPU_VK { return gvk_query_result(render3d_st, id, out) }
|
||||
gl_get_query_objectiv(id, GL_QUERY_RESULT_AVAILABLE, out)
|
||||
if out[0] == 0 { return false }
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ function gvk_alloc(render3d_st: mut Render3dState, req: bytes, want: int) -> lon
|
|||
Vk.put_i64(mai, VkMemoryAllocateInfo_allocationSize, Vk.get_i64(req, VkMemoryRequirements_size))
|
||||
Vk.put_i32(mai, VkMemoryAllocateInfo_memoryTypeIndex, t)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_mem += 1
|
||||
let r = Vk.allocate_memory(render3d_st.gvk_dev, mai, null, out)
|
||||
if r != VK_SUCCESS { print(`r3d: vulkan: vkAllocateMemory failed (VkResult {r})`); return zero }
|
||||
render3d_st.gvk_n_allocs += 1
|
||||
|
|
@ -338,6 +339,7 @@ function gvk_mem_raw(render3d_st: mut Render3dState, t: int, size: int, host: bo
|
|||
Vk.put_i64(mai, VkMemoryAllocateInfo_allocationSize, size_l)
|
||||
Vk.put_i32(mai, VkMemoryAllocateInfo_memoryTypeIndex, t)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_mem += 1
|
||||
let r = Vk.allocate_memory(render3d_st.gvk_dev, mai, null, out)
|
||||
if r != VK_SUCCESS { gvk_note(render3d_st, `r3d: vulkan: vkAllocateMemory of {size} bytes failed (VkResult {r}, {render3d_st.gvk_n_allocs} allocations live)`); return zero }
|
||||
render3d_st.gvk_n_allocs += 1
|
||||
|
|
@ -447,6 +449,7 @@ function gvk_mem_free(render3d_st: mut Render3dState, a: int) -> void {
|
|||
let zero: long = 0
|
||||
if b < 0 {
|
||||
if render3d_st.gvk_al_map[a] != null { Vk.unmap_memory(render3d_st.gvk_dev, render3d_st.gvk_al_mem[a]) }
|
||||
render3d_st.gvk_mk_x_mem += 1
|
||||
Vk.free_memory(render3d_st.gvk_dev, render3d_st.gvk_al_mem[a], null)
|
||||
render3d_st.gvk_n_allocs -= 1
|
||||
} else {
|
||||
|
|
@ -466,6 +469,7 @@ function gvk_mem_free(render3d_st: mut Render3dState, a: int) -> void {
|
|||
if off == 0 and n == render3d_st.gvk_blk_size[b] {
|
||||
# the block is empty again: give it back, or a world swapped out keeps its memory for good
|
||||
if render3d_st.gvk_blk_map[b] != null { Vk.unmap_memory(render3d_st.gvk_dev, render3d_st.gvk_blk_mem[b]) }
|
||||
render3d_st.gvk_mk_x_mem += 1
|
||||
Vk.free_memory(render3d_st.gvk_dev, render3d_st.gvk_blk_mem[b], null)
|
||||
render3d_st.gvk_n_allocs -= 1
|
||||
render3d_st.gvk_blk_mem[b] = zero; render3d_st.gvk_blk_map[b] = null; render3d_st.gvk_blk_kind[b] = -1; render3d_st.gvk_blk_size[b] = 0
|
||||
|
|
@ -503,17 +507,35 @@ function gvk_cmd_init(render3d_st: mut Render3dState) -> bool {
|
|||
return true
|
||||
}
|
||||
# a command buffer, begun
|
||||
function gvk_once_begin(render3d_st: Render3dState) -> pointer {
|
||||
let cbai = bytes(VkCommandBufferAllocateInfo_sizeof)
|
||||
# ---- scratch -------------------------------------------------------------------------------
|
||||
# The structs a Vulkan call reads are copied before it returns, so the ones built for a draw, a
|
||||
# pass, a barrier or a submit need not outlive it. They were each a bytes() - a malloc nothing
|
||||
# freed, several per draw: about 0.5 MB a frame, and one windowed run grew past 150 GB. They
|
||||
# come from this ring instead: one block, handed out in order and wrapped when it is used up.
|
||||
const GVK_TMP_BYTES: int = 1048576
|
||||
|
||||
function gvk_tmp(render3d_st: mut Render3dState, n: int) -> pointer {
|
||||
if render3d_st.gvk_tmp_buf == null { render3d_st.gvk_tmp_buf = bytes(GVK_TMP_BYTES) }
|
||||
let sz = (n + 15) / 16 * 16
|
||||
if sz > GVK_TMP_BYTES { print(`r3d: vulkan: {n} bytes of scratch asked for at once`); return null }
|
||||
if render3d_st.gvk_tmp_off + sz > GVK_TMP_BYTES { render3d_st.gvk_tmp_off = 0 }
|
||||
let p = mem_off(render3d_st.gvk_tmp_buf, render3d_st.gvk_tmp_off)
|
||||
render3d_st.gvk_tmp_off += sz
|
||||
return p
|
||||
}
|
||||
|
||||
function gvk_once_begin(render3d_st: mut Render3dState) -> pointer {
|
||||
let cbai = gvk_tmp(render3d_st, VkCommandBufferAllocateInfo_sizeof)
|
||||
Vk.zero(cbai, VkCommandBufferAllocateInfo_sizeof)
|
||||
Vk.put_i32(cbai, VkCommandBufferAllocateInfo_sType, VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO)
|
||||
Vk.put_i64(cbai, VkCommandBufferAllocateInfo_commandPool, render3d_st.gvk_pool)
|
||||
Vk.put_i32(cbai, VkCommandBufferAllocateInfo_level, VK_COMMAND_BUFFER_LEVEL_PRIMARY)
|
||||
Vk.put_i32(cbai, VkCommandBufferAllocateInfo_commandBufferCount, 1)
|
||||
let cbs = bytes(8)
|
||||
let cbs = gvk_tmp(render3d_st, 8)
|
||||
render3d_st.gvk_mk_cmd += 1
|
||||
if Vk.allocate_command_buffers(render3d_st.gvk_dev, cbai, cbs) != VK_SUCCESS { return null }
|
||||
let cb = Vk.get_ptr(cbs, 0)
|
||||
let cbbi = bytes(VkCommandBufferBeginInfo_sizeof)
|
||||
let cbbi = gvk_tmp(render3d_st, VkCommandBufferBeginInfo_sizeof)
|
||||
Vk.zero(cbbi, VkCommandBufferBeginInfo_sizeof)
|
||||
Vk.put_i32(cbbi, VkCommandBufferBeginInfo_sType, VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
|
||||
Vk.put_i32(cbbi, VkCommandBufferBeginInfo_flags, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT)
|
||||
|
|
@ -525,10 +547,10 @@ function gvk_once_end(render3d_st: mut Render3dState, cb: pointer) -> bool {
|
|||
gvk_frame_wait(render3d_st)
|
||||
var r = Vk.end_command_buffer(cb)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, "vkEndCommandBuffer", r) }
|
||||
let cbs = bytes(8)
|
||||
let cbs = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_ptr(cbs, 0, cb)
|
||||
Vk.reset_fences(render3d_st.gvk_dev, 1, render3d_st.gvk_fence)
|
||||
let si = bytes(VkSubmitInfo_sizeof)
|
||||
let si = gvk_tmp(render3d_st, VkSubmitInfo_sizeof)
|
||||
Vk.zero(si, VkSubmitInfo_sizeof)
|
||||
Vk.put_i32(si, VkSubmitInfo_sType, VK_STRUCTURE_TYPE_SUBMIT_INFO)
|
||||
Vk.put_i32(si, VkSubmitInfo_commandBufferCount, 1)
|
||||
|
|
@ -556,6 +578,7 @@ function gvk_inflight_on(render3d_st: mut Render3dState) -> bool {
|
|||
if render3d_st.gvk_inflight < 0 {
|
||||
render3d_st.gvk_inflight = 0
|
||||
if Os.platform() == "macos" { render3d_st.gvk_inflight = 1 }
|
||||
render3d_st.gvk_nopool = r3d_env_has(render3d_st, "R3D_VK_NOPOOL")
|
||||
if r3d_env_has(render3d_st, "R3D_VK_INFLIGHT") { render3d_st.gvk_inflight = Text.to_int(r3d_env(render3d_st, "R3D_VK_INFLIGHT")) }
|
||||
}
|
||||
return render3d_st.gvk_inflight == 1
|
||||
|
|
@ -565,10 +588,10 @@ function gvk_frame_submit(render3d_st: mut Render3dState, cb: pointer) -> bool {
|
|||
gvk_frame_wait(render3d_st)
|
||||
var r = Vk.end_command_buffer(cb)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, "vkEndCommandBuffer", r) }
|
||||
let cbs = bytes(8)
|
||||
let cbs = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_ptr(cbs, 0, cb)
|
||||
Vk.reset_fences(render3d_st.gvk_dev, 1, render3d_st.gvk_frame_fence)
|
||||
let si = bytes(VkSubmitInfo_sizeof)
|
||||
let si = gvk_tmp(render3d_st, VkSubmitInfo_sizeof)
|
||||
Vk.zero(si, VkSubmitInfo_sizeof)
|
||||
Vk.put_i32(si, VkSubmitInfo_sType, VK_STRUCTURE_TYPE_SUBMIT_INFO)
|
||||
Vk.put_i32(si, VkSubmitInfo_commandBufferCount, 1)
|
||||
|
|
@ -585,7 +608,7 @@ function gvk_frame_wait(render3d_st: mut Render3dState) -> void {
|
|||
if not render3d_st.gvk_frame_pending { return }
|
||||
let forever: long = -1
|
||||
Vk.wait_for_fences(render3d_st.gvk_dev, 1, render3d_st.gvk_frame_fence, 1, forever)
|
||||
let cbs = bytes(8)
|
||||
let cbs = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_ptr(cbs, 0, render3d_st.gvk_frame_pending_cb)
|
||||
Vk.free_command_buffers(render3d_st.gvk_dev, render3d_st.gvk_pool, 1, cbs)
|
||||
render3d_st.gvk_frame_pending = false
|
||||
|
|
@ -636,9 +659,9 @@ function gvk_query_end(render3d_st: mut Render3dState) -> void {
|
|||
Vk.cmd_write_timestamp(gvk_frame_cb(render3d_st), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, render3d_st.gvk_qpool, render3d_st.gvk_q_active * 2 + 1)
|
||||
render3d_st.gvk_q_active = -1
|
||||
}
|
||||
function gvk_query_result(render3d_st: Render3dState, id: int, out: words) -> bool {
|
||||
function gvk_query_result(render3d_st: mut Render3dState, id: int, out: words) -> bool {
|
||||
if render3d_st.gvk_qpool == 0 { return false }
|
||||
let data = bytes(16)
|
||||
let data = gvk_tmp(render3d_st, 16)
|
||||
let size: long = 16
|
||||
let stride: long = 8
|
||||
if Vk.get_query_pool_results(render3d_st.gvk_dev, render3d_st.gvk_qpool, id * 2, 2, size, data, stride, VK_QUERY_RESULT_64_BIT) != VK_SUCCESS { return false }
|
||||
|
|
@ -653,7 +676,7 @@ function gvk_label_begin(render3d_st: mut Render3dState, name: pointer) -> void
|
|||
# only inside a frame: a pass the load profiles comes before the frame's pools exist
|
||||
if render3d_st.gpu_kind != GPU_VK or render3d_st.gvk_cb == null { return }
|
||||
let cb = render3d_st.gvk_cb
|
||||
let li = bytes(VkDebugUtilsLabelEXT_sizeof)
|
||||
let li = gvk_tmp(render3d_st, VkDebugUtilsLabelEXT_sizeof)
|
||||
Vk.zero(li, VkDebugUtilsLabelEXT_sizeof)
|
||||
Vk.put_i32(li, VkDebugUtilsLabelEXT_sType, VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT)
|
||||
Vk.put_ptr(li, VkDebugUtilsLabelEXT_pLabelName, name)
|
||||
|
|
|
|||
|
|
@ -195,15 +195,16 @@ function gvk_dispatch_tex(render3d_st: mut Render3dState, c: int, params: pointe
|
|||
let nb = render3d_st.gvk_cp_nbuf[c]
|
||||
var nt = 0
|
||||
if render3d_st.gvk_cp_ntex != null and c < len(render3d_st.gvk_cp_ntex) { nt = render3d_st.gvk_cp_ntex[c] }
|
||||
let dsai = bytes(VkDescriptorSetAllocateInfo_sizeof)
|
||||
let dsai = gvk_tmp(render3d_st, VkDescriptorSetAllocateInfo_sizeof)
|
||||
Vk.zero(dsai, VkDescriptorSetAllocateInfo_sizeof)
|
||||
Vk.put_i32(dsai, VkDescriptorSetAllocateInfo_sType, VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO)
|
||||
Vk.put_i64(dsai, VkDescriptorSetAllocateInfo_descriptorPool, render3d_st.gvk_dpool)
|
||||
Vk.put_i32(dsai, VkDescriptorSetAllocateInfo_descriptorSetCount, 1)
|
||||
let layouts = bytes(8)
|
||||
let layouts = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_i64(layouts, 0, render3d_st.gvk_cp_dsl[c])
|
||||
Vk.put_ptr(dsai, VkDescriptorSetAllocateInfo_pSetLayouts, layouts)
|
||||
let sets = bytes(8)
|
||||
let sets = gvk_tmp(render3d_st, 8)
|
||||
render3d_st.gvk_mk_set += 1
|
||||
let r = Vk.allocate_descriptor_sets(render3d_st.gvk_dev, dsai, sets)
|
||||
if r != VK_SUCCESS { gvk_fail(render3d_st, "vkAllocateDescriptorSets (compute)", r); return }
|
||||
let set = Vk.get_i64(sets, 0)
|
||||
|
|
@ -212,11 +213,11 @@ function gvk_dispatch_tex(render3d_st: mut Render3dState, c: int, params: pointe
|
|||
let ww = VkWriteDescriptorSet_sizeof
|
||||
let bw = VkDescriptorBufferInfo_sizeof
|
||||
let iw = VkDescriptorImageInfo_sizeof
|
||||
let writes = bytes(ww * (nb + 1 + nt))
|
||||
let writes = gvk_tmp(render3d_st, ww * (nb + 1 + nt))
|
||||
Vk.zero(writes, ww * (nb + 1 + nt))
|
||||
let infos = bytes(bw * (nb + 1))
|
||||
let infos = gvk_tmp(render3d_st, bw * (nb + 1))
|
||||
Vk.zero(infos, bw * (nb + 1))
|
||||
let iis = bytes(iw * (nt + 1))
|
||||
let iis = gvk_tmp(render3d_st, iw * (nt + 1))
|
||||
Vk.zero(iis, iw * (nt + 1))
|
||||
for k in 0 .. nb + 1 {
|
||||
var buf = render3d_st.gvk_ring_buf
|
||||
|
|
@ -254,7 +255,7 @@ function gvk_dispatch_tex(render3d_st: mut Render3dState, c: int, params: pointe
|
|||
Vk.cmd_bind_pipeline(cb, VK_PIPELINE_BIND_POINT_COMPUTE, render3d_st.gvk_cp_pipe[c])
|
||||
Vk.cmd_bind_descriptor_sets(cb, VK_PIPELINE_BIND_POINT_COMPUTE, render3d_st.gvk_cp_layout[c], 0, 1, sets, 0, null)
|
||||
Vk.cmd_dispatch(cb, gx, gy, gz)
|
||||
let mb = bytes(VkMemoryBarrier_sizeof)
|
||||
let mb = gvk_tmp(render3d_st, VkMemoryBarrier_sizeof)
|
||||
Vk.zero(mb, VkMemoryBarrier_sizeof)
|
||||
Vk.put_i32(mb, VkMemoryBarrier_sType, VK_STRUCTURE_TYPE_MEMORY_BARRIER)
|
||||
Vk.put_i32(mb, VkMemoryBarrier_srcAccessMask, VK_ACCESS_SHADER_WRITE_BIT)
|
||||
|
|
@ -704,6 +705,7 @@ function gvk_frame_init(render3d_st: mut Render3dState) -> bool {
|
|||
let out = bytes(8)
|
||||
render3d_st.gvk_dpools = new []long
|
||||
for k in 0 .. 2 {
|
||||
render3d_st.gvk_mk_dpool += 1
|
||||
let r = Vk.create_descriptor_pool(render3d_st.gvk_dev, dpci, null, out)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, "vkCreateDescriptorPool", r) }
|
||||
push(render3d_st.gvk_dpools, gvk_handle(out))
|
||||
|
|
@ -717,6 +719,8 @@ function gvk_frame_init(render3d_st: mut Render3dState) -> bool {
|
|||
}
|
||||
|
||||
function gvk_frame_reset(render3d_st: mut Render3dState) -> void {
|
||||
# what MoltenVK autoreleased last frame goes back here (a no-op off macOS); R3D_VK_NOPOOL=1 for an A/B
|
||||
if not render3d_st.gvk_nopool { Vk.frame_pool() }
|
||||
let slot = render3d_st.gvk_frame_no & 1
|
||||
render3d_st.gvk_ring_off = slot * GVK_RING_BYTES
|
||||
render3d_st.gvk_ring_end = (slot + 1) * GVK_RING_BYTES
|
||||
|
|
@ -756,6 +760,7 @@ function gvk_kpool_make(render3d_st: mut Render3dState) -> bool {
|
|||
Vk.put_i32(dpci, VkDescriptorPoolCreateInfo_poolSizeCount, 2)
|
||||
Vk.put_ptr(dpci, VkDescriptorPoolCreateInfo_pPoolSizes, sizes)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_dpool += 1
|
||||
let r = Vk.create_descriptor_pool(render3d_st.gvk_dev, dpci, null, out)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, "vkCreateDescriptorPool (kept sets)", r) }
|
||||
render3d_st.gvk_kpool = gvk_handle(out)
|
||||
|
|
@ -764,8 +769,13 @@ function gvk_kpool_make(render3d_st: mut Render3dState) -> bool {
|
|||
}
|
||||
|
||||
function gvk_sc_clear(render3d_st: mut Render3dState) -> void {
|
||||
render3d_st.gvk_sc_prog = new []int; render3d_st.gvk_sc_koff = new []int; render3d_st.gvk_sc_set = new []long; render3d_st.gvk_sc_next = new []int
|
||||
render3d_st.gvk_sc_keys = new []long
|
||||
# emptied, not replaced: five fresh lists each time the pool filled were never given back
|
||||
if render3d_st.gvk_sc_prog == null {
|
||||
render3d_st.gvk_sc_prog = new []int; render3d_st.gvk_sc_koff = new []int; render3d_st.gvk_sc_set = new []long; render3d_st.gvk_sc_next = new []int
|
||||
render3d_st.gvk_sc_keys = new []long
|
||||
}
|
||||
List.clear(render3d_st.gvk_sc_prog); List.clear(render3d_st.gvk_sc_koff); List.clear(render3d_st.gvk_sc_set); List.clear(render3d_st.gvk_sc_next)
|
||||
List.clear(render3d_st.gvk_sc_keys)
|
||||
if render3d_st.gvk_sc_head == null { render3d_st.gvk_sc_head = words(4096) }
|
||||
for i in 0 .. 4096 { render3d_st.gvk_sc_head[i] = -1 }
|
||||
}
|
||||
|
|
@ -863,6 +873,7 @@ function gvk_sc_make(render3d_st: mut Render3dState, p: int, nt: int) -> long {
|
|||
Vk.put_i32(dsai, VkDescriptorSetAllocateInfo_descriptorSetCount, 1)
|
||||
Vk.put_i64(layouts, 0, render3d_st.gvk_prog_dsl[p])
|
||||
Vk.put_ptr(dsai, VkDescriptorSetAllocateInfo_pSetLayouts, layouts)
|
||||
render3d_st.gvk_mk_set += 1
|
||||
r = Vk.allocate_descriptor_sets(render3d_st.gvk_dev, dsai, sets)
|
||||
if r == VK_SUCCESS { tries = 2 } else { gvk_kpool_reset(render3d_st); tries += 1 }
|
||||
}
|
||||
|
|
@ -1011,9 +1022,10 @@ function gvk_frame_cb(render3d_st: mut Render3dState) -> pointer {
|
|||
# on its own. Keyed by the image's generation, so a replaced image never reuses a stale view.
|
||||
function gvk_view_of(render3d_st: mut Render3dState, tex: int, layer1: int) -> long {
|
||||
if layer1 == 0 and render3d_st.gvk_tex_levels[tex] <= 1 and render3d_st.gvk_tex_layers[tex] <= 1 { return render3d_st.gvk_tex_view[tex] }
|
||||
let key = `{tex}:{render3d_st.gvk_tex_gen[tex]}:{layer1}`
|
||||
if render3d_st.gvk_layer_views == null { render3d_st.gvk_layer_views = new []string; render3d_st.gvk_layer_view = new []long }
|
||||
for i in 0 .. len(render3d_st.gvk_layer_views) { if render3d_st.gvk_layer_views[i] == key { return render3d_st.gvk_layer_view[i] } }
|
||||
# keyed by numbers, not a string built on every call: the texture, its generation and the layer
|
||||
let key = render3d_st.gvk_tex_gen[tex] * 4096 + layer1
|
||||
if render3d_st.gvk_layer_views == null { render3d_st.gvk_layer_views = new []int; render3d_st.gvk_layer_view = new []long; render3d_st.gvk_layer_view_tex = new []int }
|
||||
for i in 0 .. len(render3d_st.gvk_layer_views) { if render3d_st.gvk_layer_view_tex[i] == tex and render3d_st.gvk_layer_views[i] == key { return render3d_st.gvk_layer_view[i] } }
|
||||
let depth = render3d_st.gvk_tex_vkfmt[tex] == VK_FORMAT_D32_SFLOAT
|
||||
let vci = bytes(VkImageViewCreateInfo_sizeof)
|
||||
Vk.zero(vci, VkImageViewCreateInfo_sizeof)
|
||||
|
|
@ -1028,16 +1040,18 @@ function gvk_view_of(render3d_st: mut Render3dState, tex: int, layer1: int) -> l
|
|||
Vk.put_i32(vci, sr + VkImageSubresourceRange_layerCount, 1)
|
||||
let out = bytes(8)
|
||||
let zero: long = 0
|
||||
render3d_st.gvk_mk_view += 1
|
||||
if Vk.create_image_view(render3d_st.gvk_dev, vci, null, out) != VK_SUCCESS { return zero }
|
||||
push(render3d_st.gvk_layer_views, key)
|
||||
push(render3d_st.gvk_layer_view, gvk_handle(out))
|
||||
push(render3d_st.gvk_layer_view_tex, tex)
|
||||
return gvk_handle(out)
|
||||
}
|
||||
# the layer range a barrier for an attachment covers: the whole image unless one layer is drawn
|
||||
function gvk_att_barrier(render3d_st: Render3dState, cb: pointer, tex: int, layer1: int, depth: bool, old_layout: int, new_layout: int) -> void {
|
||||
function gvk_att_barrier(render3d_st: mut Render3dState, cb: pointer, tex: int, layer1: int, depth: bool, old_layout: int, new_layout: int) -> void {
|
||||
# an attachment whose image was never made (no memory for it) has nothing to transition
|
||||
if tex <= 0 or tex >= len(render3d_st.gvk_tex_image) or render3d_st.gvk_tex_image[tex] == 0 { return }
|
||||
let b = bytes(VkImageMemoryBarrier_sizeof)
|
||||
let b = gvk_tmp(render3d_st, VkImageMemoryBarrier_sizeof)
|
||||
Vk.zero(b, VkImageMemoryBarrier_sizeof)
|
||||
Vk.put_i32(b, VkImageMemoryBarrier_sType, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER)
|
||||
Vk.put_i32(b, VkImageMemoryBarrier_srcAccessMask, gvk_layout_access(old_layout))
|
||||
|
|
@ -1085,7 +1099,7 @@ function gvk_pass_begin(render3d_st: mut Render3dState, rec: words, rec_o: int)
|
|||
let cb = gvk_frame_cb(render3d_st)
|
||||
gvk_pass_collect(render3d_st, render3d_st.gvk_fb_cur, rec, rec_o)
|
||||
let aw = VkRenderingAttachmentInfo_sizeof
|
||||
let catt = bytes(aw * 3)
|
||||
let catt = gvk_tmp(render3d_st, aw * 3)
|
||||
Vk.zero(catt, aw * 3)
|
||||
render3d_st.gvk_pass_w = 0
|
||||
render3d_st.gvk_pass_h = 0
|
||||
|
|
@ -1108,7 +1122,7 @@ function gvk_pass_begin(render3d_st: mut Render3dState, rec: words, rec_o: int)
|
|||
render3d_st.gvk_pass_samples = gvk_tex_samples_of(render3d_st, tex)
|
||||
if render3d_st.gvk_pass_w == 0 { render3d_st.gvk_pass_w = gvk_tex_w(render3d_st, tex); render3d_st.gvk_pass_h = gvk_tex_h(render3d_st, tex) }
|
||||
}
|
||||
let datt = bytes(aw)
|
||||
let datt = gvk_tmp(render3d_st, aw)
|
||||
Vk.zero(datt, aw)
|
||||
let dtex = render3d_st.gvk_pass_dep[0]
|
||||
if dtex > 0 {
|
||||
|
|
@ -1126,7 +1140,7 @@ function gvk_pass_begin(render3d_st: mut Render3dState, rec: words, rec_o: int)
|
|||
if render3d_st.gvk_pass_w == 0 { render3d_st.gvk_pass_w = gvk_tex_w(render3d_st, dtex); render3d_st.gvk_pass_h = gvk_tex_h(render3d_st, dtex) }
|
||||
}
|
||||
render3d_st.gvk_clear_bits = 0
|
||||
let ri = bytes(VkRenderingInfo_sizeof)
|
||||
let ri = gvk_tmp(render3d_st, VkRenderingInfo_sizeof)
|
||||
Vk.zero(ri, VkRenderingInfo_sizeof)
|
||||
Vk.put_i32(ri, VkRenderingInfo_sType, VK_STRUCTURE_TYPE_RENDERING_INFO)
|
||||
Vk.put_i32(ri, VkRenderingInfo_renderArea + VkRect2D_extent + VkExtent2D_width, render3d_st.gvk_pass_w)
|
||||
|
|
@ -1157,7 +1171,7 @@ function gvk_clear(render3d_st: mut Render3dState, mask: int, rec: words, rec_o:
|
|||
if not render3d_st.gvk_in_pass { render3d_st.gvk_clear_bits = render3d_st.gvk_clear_bits | mask; return }
|
||||
let cb = render3d_st.gvk_cb
|
||||
let caw = VkClearAttachment_sizeof
|
||||
let atts = bytes(caw * 4)
|
||||
let atts = gvk_tmp(render3d_st, caw * 4)
|
||||
Vk.zero(atts, caw * 4)
|
||||
var n = 0
|
||||
if (mask & GL_COLOR_BUFFER_BIT) != 0 {
|
||||
|
|
@ -1174,7 +1188,7 @@ function gvk_clear(render3d_st: mut Render3dState, mask: int, rec: words, rec_o:
|
|||
n += 1
|
||||
}
|
||||
if n == 0 { return }
|
||||
let rect = bytes(VkClearRect_sizeof)
|
||||
let rect = gvk_tmp(render3d_st, VkClearRect_sizeof)
|
||||
Vk.zero(rect, VkClearRect_sizeof)
|
||||
Vk.put_i32(rect, VkClearRect_rect + VkRect2D_extent + VkExtent2D_width, render3d_st.gvk_pass_w)
|
||||
Vk.put_i32(rect, VkClearRect_rect + VkRect2D_extent + VkExtent2D_height, render3d_st.gvk_pass_h)
|
||||
|
|
@ -1187,8 +1201,8 @@ function gvk_tex_h(render3d_st: Render3dState, tex: int) -> int { return render3
|
|||
|
||||
# viewport and scissor for the draw; OpenGL's rows count from the bottom and so do a Vulkan
|
||||
# target's here (no y flip), so both pass straight through
|
||||
function gvk_set_view(render3d_st: Render3dState, cb: pointer) -> void {
|
||||
let vp = bytes(VkViewport_sizeof)
|
||||
function gvk_set_view(render3d_st: mut Render3dState, cb: pointer) -> void {
|
||||
let vp = gvk_tmp(render3d_st, VkViewport_sizeof)
|
||||
Vk.zero(vp, VkViewport_sizeof)
|
||||
Vk.put_i32(vp, VkViewport_x, float_bits(float(render3d_st.gvk_vp[0])))
|
||||
Vk.put_i32(vp, VkViewport_y, float_bits(float(render3d_st.gvk_vp[1])))
|
||||
|
|
@ -1196,7 +1210,7 @@ function gvk_set_view(render3d_st: Render3dState, cb: pointer) -> void {
|
|||
Vk.put_i32(vp, VkViewport_height, float_bits(float(render3d_st.gvk_vp[3])))
|
||||
Vk.put_i32(vp, VkViewport_maxDepth, 0x3F800000)
|
||||
Vk.cmd_set_viewport(cb, 0, 1, vp)
|
||||
let sc = bytes(VkRect2D_sizeof)
|
||||
let sc = gvk_tmp(render3d_st, VkRect2D_sizeof)
|
||||
Vk.zero(sc, VkRect2D_sizeof)
|
||||
if render3d_st.gvk_sc[0] == 1 {
|
||||
Vk.put_i32(sc, VkRect2D_offset + VkOffset2D_x, render3d_st.gvk_sc[1])
|
||||
|
|
@ -1238,16 +1252,17 @@ function gvk_draw(render3d_st: mut Render3dState, p: int, m: Mesh, st: GvkState,
|
|||
let set = gvk_draw_set(render3d_st, p, tx, tx_w, tx_cap)
|
||||
if set == 0 { return }
|
||||
if prof { render3d_st.gvk_us_set = render3d_st.gvk_us_set + (gl_now_us() - t1) }
|
||||
let sets = bytes(8)
|
||||
let sets = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_i64(sets, 0, set)
|
||||
Vk.cmd_bind_descriptor_sets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, render3d_st.gvk_prog_layout[p], 0, 1, sets, render3d_st.gvk_set_ndyn, render3d_st.gvk_set_offs)
|
||||
let v = render3d_st.gvk_prog_var[p]
|
||||
if m != null and m.attrs != null {
|
||||
# the same bindings, in the same order, as gvk_pipeline gave the layout
|
||||
let bufs = bytes(8 * (GPU_MAX_VBUFS + 1))
|
||||
let offs = bytes(8 * (GPU_MAX_VBUFS + 1))
|
||||
let bufs = gvk_tmp(render3d_st, 8 * (GPU_MAX_VBUFS + 1))
|
||||
let offs = gvk_tmp(render3d_st, 8 * (GPU_MAX_VBUFS + 1))
|
||||
Vk.zero(offs, 8 * (GPU_MAX_VBUFS + 1))
|
||||
let seen = words(GPU_MAX_VBUFS)
|
||||
if render3d_st.gvk_seen == null { render3d_st.gvk_seen = words(GPU_MAX_VBUFS) }
|
||||
let seen = render3d_st.gvk_seen
|
||||
var nbd = 0
|
||||
for i in 0 .. m.n_attrs {
|
||||
let o = i * GPU_ATTR_W
|
||||
|
|
@ -1510,7 +1525,7 @@ function gvk_resolve(render3d_st: mut Render3dState, cb: pointer, src: int, dst:
|
|||
gvk_att_barrier(render3d_st, cb, src, 0, depth, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, layout)
|
||||
gvk_att_barrier(render3d_st, cb, dst, 0, depth, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, layout)
|
||||
let aw = VkRenderingAttachmentInfo_sizeof
|
||||
let att = bytes(aw)
|
||||
let att = gvk_tmp(render3d_st, aw)
|
||||
Vk.zero(att, aw)
|
||||
Vk.put_i32(att, VkRenderingAttachmentInfo_sType, VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO)
|
||||
Vk.put_i64(att, VkRenderingAttachmentInfo_imageView, gvk_view_of(render3d_st, src, 0))
|
||||
|
|
@ -1520,7 +1535,7 @@ function gvk_resolve(render3d_st: mut Render3dState, cb: pointer, src: int, dst:
|
|||
Vk.put_i32(att, VkRenderingAttachmentInfo_resolveImageLayout, layout)
|
||||
Vk.put_i32(att, VkRenderingAttachmentInfo_loadOp, VK_ATTACHMENT_LOAD_OP_LOAD)
|
||||
Vk.put_i32(att, VkRenderingAttachmentInfo_storeOp, VK_ATTACHMENT_STORE_OP_STORE)
|
||||
let ri = bytes(VkRenderingInfo_sizeof)
|
||||
let ri = gvk_tmp(render3d_st, VkRenderingInfo_sizeof)
|
||||
Vk.zero(ri, VkRenderingInfo_sizeof)
|
||||
Vk.put_i32(ri, VkRenderingInfo_sType, VK_STRUCTURE_TYPE_RENDERING_INFO)
|
||||
Vk.put_i32(ri, VkRenderingInfo_renderArea + VkRect2D_extent + VkExtent2D_width, w)
|
||||
|
|
@ -1536,9 +1551,9 @@ function gvk_resolve(render3d_st: mut Render3dState, cb: pointer, src: int, dst:
|
|||
function gvk_copy(render3d_st: mut Render3dState, cb: pointer, src: int, dst: int, depth: bool, w: int, h: int) -> void {
|
||||
if src <= 0 or dst <= 0 or render3d_st.gvk_tex_image[src] == 0 or render3d_st.gvk_tex_image[dst] == 0 { return }
|
||||
if gvk_tex_samples_of(render3d_st, src) > 1 and gvk_tex_samples_of(render3d_st, dst) == 1 { gvk_resolve(render3d_st, cb, src, dst, depth, w, h); return }
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[src], depth, 0, 1, render3d_st.gvk_tex_layers[src], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[dst], depth, 0, 1, render3d_st.gvk_tex_layers[dst], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let ic = bytes(VkImageCopy_sizeof)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[src], depth, 0, 1, render3d_st.gvk_tex_layers[src], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[dst], depth, 0, 1, render3d_st.gvk_tex_layers[dst], VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let ic = gvk_tmp(render3d_st, VkImageCopy_sizeof)
|
||||
Vk.zero(ic, VkImageCopy_sizeof)
|
||||
var aspect = VK_IMAGE_ASPECT_COLOR_BIT
|
||||
if depth { aspect = VK_IMAGE_ASPECT_DEPTH_BIT }
|
||||
|
|
@ -1550,8 +1565,8 @@ function gvk_copy(render3d_st: mut Render3dState, cb: pointer, src: int, dst: in
|
|||
Vk.put_i32(ic, VkImageCopy_extent + VkExtent3D_height, h)
|
||||
Vk.put_i32(ic, VkImageCopy_extent + VkExtent3D_depth, 1)
|
||||
Vk.cmd_copy_image(cb, render3d_st.gvk_tex_image[src], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, render3d_st.gvk_tex_image[dst], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ic)
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[src], depth, 0, 1, render3d_st.gvk_tex_layers[src], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[dst], depth, 0, 1, render3d_st.gvk_tex_layers[dst], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[src], depth, 0, 1, render3d_st.gvk_tex_layers[src], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[dst], depth, 0, 1, render3d_st.gvk_tex_layers[dst], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
}
|
||||
function gvk_blit(render3d_st: mut Render3dState, w: int, h: int, mask: int) -> void {
|
||||
gvk_pass_end(render3d_st)
|
||||
|
|
@ -1725,20 +1740,20 @@ function gvk_present_window(render3d_st: mut Render3dState) -> void {
|
|||
Time.sleep_us(16000)
|
||||
return
|
||||
}
|
||||
if render3d_st.gvk_swap_stale { gvk_once_end(render3d_st, cb); render3d_st.gvk_cb = null; gvk_swap_make(render3d_st, render3d_st.gvk_swap_w, render3d_st.gvk_swap_h); return }
|
||||
let idx = bytes(4)
|
||||
if render3d_st.gvk_swap_stale { gvk_once_end(render3d_st, cb); render3d_st.gvk_cb = null; print("r3d: vulkan: swapchain remade at acquire"); gvk_swap_make(render3d_st, render3d_st.gvk_swap_w, render3d_st.gvk_swap_h); return }
|
||||
let idx = gvk_tmp(render3d_st, 4)
|
||||
Vk.reset_fences(render3d_st.gvk_dev, 1, render3d_st.gvk_acq_fence)
|
||||
let forever: long = -1
|
||||
let zero: long = 0
|
||||
var r = Vk.acquire_next_image_khr(render3d_st.gvk_dev, render3d_st.gvk_swap, forever, zero, Vk.get_i64(render3d_st.gvk_acq_fence, 0), idx)
|
||||
if r == VK_ERROR_OUT_OF_DATE_KHR { gvk_once_end(render3d_st, cb); render3d_st.gvk_cb = null; gvk_swap_make(render3d_st, render3d_st.gvk_swap_w, render3d_st.gvk_swap_h); return }
|
||||
if r == VK_ERROR_OUT_OF_DATE_KHR { gvk_once_end(render3d_st, cb); render3d_st.gvk_cb = null; print("r3d: vulkan: swapchain remade at acquire"); gvk_swap_make(render3d_st, render3d_st.gvk_swap_w, render3d_st.gvk_swap_h); return }
|
||||
Vk.wait_for_fences(render3d_st.gvk_dev, 1, render3d_st.gvk_acq_fence, 1, forever)
|
||||
let i = Vk.get_i32(idx, 0)
|
||||
let dst = Vk.get_i64(render3d_st.gvk_swap_images, i * 8)
|
||||
let src = render3d_st.gvk_tex_image[render3d_st.gvk_screen_color]
|
||||
gvk_barrier(cb, src, false, 0, 1, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(cb, dst, false, 0, 1, 1, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let blit = bytes(VkImageBlit_sizeof)
|
||||
gvk_barrier(render3d_st, cb, src, false, 0, 1, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, dst, false, 0, 1, 1, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let blit = gvk_tmp(render3d_st, VkImageBlit_sizeof)
|
||||
Vk.zero(blit, VkImageBlit_sizeof)
|
||||
Vk.put_i32(blit, VkImageBlit_srcSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
Vk.put_i32(blit, VkImageBlit_srcSubresource + VkImageSubresourceLayers_layerCount, 1)
|
||||
|
|
@ -1752,14 +1767,14 @@ function gvk_present_window(render3d_st: mut Render3dState) -> void {
|
|||
Vk.put_i32(blit, VkImageBlit_dstOffsets + VkOffset3D_sizeof + VkOffset3D_y, render3d_st.gvk_swap_h)
|
||||
Vk.put_i32(blit, VkImageBlit_dstOffsets + VkOffset3D_sizeof + VkOffset3D_z, 1)
|
||||
Vk.cmd_blit_image(cb, src, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blit, VK_FILTER_LINEAR)
|
||||
gvk_barrier(cb, src, false, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(cb, dst, false, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
gvk_barrier(render3d_st, cb, src, false, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, dst, false, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
|
||||
if gvk_inflight_on(render3d_st) { gvk_frame_submit(render3d_st, cb) } else { gvk_once_end(render3d_st, cb) }
|
||||
render3d_st.gvk_cb = null
|
||||
let pi = bytes(VkPresentInfoKHR_sizeof)
|
||||
let pi = gvk_tmp(render3d_st, VkPresentInfoKHR_sizeof)
|
||||
Vk.zero(pi, VkPresentInfoKHR_sizeof)
|
||||
Vk.put_i32(pi, VkPresentInfoKHR_sType, VK_STRUCTURE_TYPE_PRESENT_INFO_KHR)
|
||||
let chains = bytes(8)
|
||||
let chains = gvk_tmp(render3d_st, 8)
|
||||
Vk.put_i64(chains, 0, render3d_st.gvk_swap)
|
||||
Vk.put_i32(pi, VkPresentInfoKHR_swapchainCount, 1)
|
||||
Vk.put_ptr(pi, VkPresentInfoKHR_pSwapchains, chains)
|
||||
|
|
@ -1779,6 +1794,8 @@ function gvk_resize_check(render3d_st: mut Render3dState) -> bool {
|
|||
let h = render3d_st.gvk_size_buf[1]
|
||||
if w <= 0 or h <= 0 { return false }
|
||||
if w == gl_width() and h == gl_height() and not render3d_st.gvk_swap_stale { return false }
|
||||
# a remake is rare (a resize); said, so one on every frame shows in the log
|
||||
print(`r3d: vulkan: swapchain remade {w}x{h} (was {gl_width()}x{gl_height()}, stale {render3d_st.gvk_swap_stale})`)
|
||||
gvk_flush(render3d_st)
|
||||
gl_set_drawable(w, h)
|
||||
gvk_screen_make(render3d_st, w, h)
|
||||
|
|
@ -1816,11 +1833,26 @@ function gvk_prof_frame(render3d_st: mut Render3dState) -> void {
|
|||
if render3d_st.gvk_n_asked != render3d_st.gvk_n_draws {
|
||||
print(`r3d: vulkan: {(render3d_st.gvk_n_asked - render3d_st.gvk_n_draws) / f} draws a frame were asked for and not made ({render3d_st.gvk_n_asked / f} asked, {render3d_st.gvk_n_draws / f} made)`)
|
||||
}
|
||||
gvk_prof_made(render3d_st)
|
||||
let zero: long = 0
|
||||
render3d_st.gvk_us_pipe = zero; render3d_st.gvk_us_set = zero; render3d_st.gvk_us_draw = zero
|
||||
render3d_st.gvk_n_draws = 0; render3d_st.gvk_n_asked = 0; render3d_st.gvk_n_flush = 0; render3d_st.gvk_prof_frames = 0; render3d_st.gvk_n_pipe_new = 0
|
||||
}
|
||||
|
||||
# what was made and destroyed over those frames, and how long the caches are: a kind made every
|
||||
# frame and never destroyed, or a cache that only grows, is a leak
|
||||
function gvk_prof_made(render3d_st: mut Render3dState) -> void {
|
||||
let r = render3d_st
|
||||
print(`r3d: vulkan made/destroyed: images {r.gvk_mk_img}/{r.gvk_mk_x_img}, views {r.gvk_mk_view}/{r.gvk_mk_x_view}, buffers {r.gvk_mk_buf}/{r.gvk_mk_x_buf}, memory {r.gvk_mk_mem}/{r.gvk_mk_x_mem}, samplers {r.gvk_mk_smp}, sets {r.gvk_mk_set}, pools {r.gvk_mk_dpool}, cmds {r.gvk_mk_cmd}`)
|
||||
print(`r3d: vulkan caches: layer views {gvk_len_i(r.gvk_layer_views)}, pipelines {gvk_len_s(r.gvk_pipe_keys)}, layouts {gvk_len_s(r.gvk_layout_keys)}, pipe cache {gvk_len_i(r.gvk_pc_prog)}, retired {gvk_len_l(r.gvk_retired_buf)}, buffers {gvk_len_l(r.gvk_buf)}, allocs {r.gvk_n_allocs}`)
|
||||
render3d_st.gvk_mk_img = 0; render3d_st.gvk_mk_x_img = 0; render3d_st.gvk_mk_view = 0; render3d_st.gvk_mk_x_view = 0
|
||||
render3d_st.gvk_mk_buf = 0; render3d_st.gvk_mk_x_buf = 0; render3d_st.gvk_mk_mem = 0; render3d_st.gvk_mk_x_mem = 0
|
||||
render3d_st.gvk_mk_smp = 0; render3d_st.gvk_mk_set = 0; render3d_st.gvk_mk_dpool = 0; render3d_st.gvk_mk_cmd = 0
|
||||
}
|
||||
function gvk_len_s(xs: []string) -> int { if xs == null { return 0 }; return len(xs) }
|
||||
function gvk_len_i(xs: []int) -> int { if xs == null { return 0 }; return len(xs) }
|
||||
function gvk_len_l(xs: []long) -> int { if xs == null { return 0 }; return len(xs) }
|
||||
|
||||
# ---- the pipeline cache, by integers -----------------------------------------------------------
|
||||
# gvk_pipeline builds and keys pipelines by a string; a draw only needs to find one it already has.
|
||||
# A mesh carries an interned layout id (its recorded layout, buffers named by order), the render
|
||||
|
|
|
|||
|
|
@ -88,10 +88,10 @@ function gvk_layout_access(layout: int) -> int {
|
|||
return 0
|
||||
}
|
||||
# levels [base, base + n) of every layer of an image, from one layout to another
|
||||
function gvk_barrier(cb: pointer, image: long, depth: bool, base: int, n: int, layers: int, old_layout: int, new_layout: int) -> void {
|
||||
function gvk_barrier(render3d_st: mut Render3dState, cb: pointer, image: long, depth: bool, base: int, n: int, layers: int, old_layout: int, new_layout: int) -> void {
|
||||
# an image that was never made (its memory could not be had) has nothing to transition
|
||||
if image == 0 { return }
|
||||
let b = bytes(VkImageMemoryBarrier_sizeof)
|
||||
let b = gvk_tmp(render3d_st, VkImageMemoryBarrier_sizeof)
|
||||
Vk.zero(b, VkImageMemoryBarrier_sizeof)
|
||||
Vk.put_i32(b, VkImageMemoryBarrier_sType, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER)
|
||||
Vk.put_i32(b, VkImageMemoryBarrier_srcAccessMask, gvk_layout_access(old_layout))
|
||||
|
|
@ -122,6 +122,7 @@ function gvk_staging(render3d_st: mut Render3dState, n: int, usage: int) -> poin
|
|||
Vk.put_i32(bci, VkBufferCreateInfo_usage, usage)
|
||||
Vk.put_i32(bci, VkBufferCreateInfo_sharingMode, VK_SHARING_MODE_EXCLUSIVE)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_buf += 1
|
||||
if Vk.create_buffer(render3d_st.gvk_dev, bci, null, out) != VK_SUCCESS { return null }
|
||||
render3d_st.gvk_st_buf = gvk_handle(out)
|
||||
let req = bytes(VkMemoryRequirements_sizeof)
|
||||
|
|
@ -136,7 +137,9 @@ function gvk_staging(render3d_st: mut Render3dState, n: int, usage: int) -> poin
|
|||
function gvk_staging_free(render3d_st: mut Render3dState) -> void {
|
||||
gvk_frame_wait(render3d_st) # the frame in flight may still read it
|
||||
Vk.unmap_memory(render3d_st.gvk_dev, render3d_st.gvk_st_mem)
|
||||
render3d_st.gvk_mk_x_buf += 1
|
||||
Vk.destroy_buffer(render3d_st.gvk_dev, render3d_st.gvk_st_buf, null)
|
||||
render3d_st.gvk_mk_x_mem += 1
|
||||
Vk.free_memory(render3d_st.gvk_dev, render3d_st.gvk_st_mem, null)
|
||||
render3d_st.gvk_n_allocs -= 1
|
||||
}
|
||||
|
|
@ -175,6 +178,7 @@ function gvk_tex_storage(render3d_st: mut Render3dState, tex: int, array: bool,
|
|||
Vk.put_i32(ici, VkImageCreateInfo_sharingMode, VK_SHARING_MODE_EXCLUSIVE)
|
||||
Vk.put_i32(ici, VkImageCreateInfo_initialLayout, VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_img += 1
|
||||
var r = Vk.create_image(render3d_st.gvk_dev, ici, null, out)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, `vkCreateImage {w}x{h}x{layers} format {vkfmt}`, r) }
|
||||
let image = gvk_handle(out)
|
||||
|
|
@ -186,6 +190,7 @@ function gvk_tex_storage(render3d_st: mut Render3dState, tex: int, array: bool,
|
|||
# no memory for it (one allocation per resource meets the driver's allocation limit long before
|
||||
# the card is full): say so instead of binding a null allocation, which the driver may accept
|
||||
if mem == 0 {
|
||||
render3d_st.gvk_mk_x_img += 1
|
||||
Vk.destroy_image(render3d_st.gvk_dev, image, null)
|
||||
return gvk_fail(render3d_st, `no device memory for a {w}x{h}x{layers} image ({render3d_st.gvk_n_allocs} allocations live)`, VK_ERROR_OUT_OF_DEVICE_MEMORY)
|
||||
}
|
||||
|
|
@ -201,6 +206,7 @@ function gvk_tex_storage(render3d_st: mut Render3dState, tex: int, array: bool,
|
|||
if depth { Vk.put_i32(vci, sr + VkImageSubresourceRange_aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) } else { Vk.put_i32(vci, sr + VkImageSubresourceRange_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT) }
|
||||
Vk.put_i32(vci, sr + VkImageSubresourceRange_levelCount, levels)
|
||||
Vk.put_i32(vci, sr + VkImageSubresourceRange_layerCount, layers)
|
||||
render3d_st.gvk_mk_view += 1
|
||||
r = Vk.create_image_view(render3d_st.gvk_dev, vci, null, out)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, "vkCreateImageView", r) }
|
||||
render3d_st.gvk_tex_image[tex] = image; render3d_st.gvk_tex_view[tex] = gvk_handle(out); render3d_st.gvk_tex_mem[tex] = mem
|
||||
|
|
@ -211,7 +217,7 @@ function gvk_tex_storage(render3d_st: mut Render3dState, tex: int, array: bool,
|
|||
if array { render3d_st.gvk_tex_array[tex] = 1 } else { render3d_st.gvk_tex_array[tex] = 0 }
|
||||
# a target starts cleared-to-nothing but readable: every level in the layout samplers expect
|
||||
let cb = gvk_once_begin(render3d_st)
|
||||
gvk_barrier(cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
return gvk_once_end(render3d_st, cb)
|
||||
}
|
||||
|
||||
|
|
@ -248,7 +254,8 @@ function gvk_tex_upload(render3d_st: mut Render3dState, tex: int, ifmt: int, w:
|
|||
let n = texels * cout * bout
|
||||
let dst = gvk_staging(render3d_st, n, VK_BUFFER_USAGE_TRANSFER_SRC_BIT)
|
||||
if dst == null { print("r3d: vulkan: no staging buffer for an upload"); return false }
|
||||
let buf = bytes(n)
|
||||
# written straight into the mapped staging memory: a copy of its own was never freed
|
||||
let buf: pointer = dst
|
||||
if cin == cout and bin == bout and not (bin == 2 and render3d_st.gvk_unpack_swap) {
|
||||
mem_copy(buf, data, n)
|
||||
} else {
|
||||
|
|
@ -281,12 +288,11 @@ function gvk_tex_upload(render3d_st: mut Render3dState, tex: int, ifmt: int, w:
|
|||
}
|
||||
}
|
||||
}
|
||||
mem_copy(dst, buf, n)
|
||||
let image = render3d_st.gvk_tex_image[tex]
|
||||
let depth = gvk_is_depth(ifmt)
|
||||
let levels = render3d_st.gvk_tex_levels[tex]
|
||||
let cb = gvk_once_begin(render3d_st)
|
||||
gvk_barrier(cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let bic = bytes(VkBufferImageCopy_sizeof)
|
||||
Vk.zero(bic, VkBufferImageCopy_sizeof)
|
||||
if depth { Vk.put_i32(bic, VkBufferImageCopy_imageSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) }
|
||||
|
|
@ -296,7 +302,7 @@ function gvk_tex_upload(render3d_st: mut Render3dState, tex: int, ifmt: int, w:
|
|||
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_height, h)
|
||||
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_depth, 1)
|
||||
Vk.cmd_copy_buffer_to_image(cb, render3d_st.gvk_st_buf, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, bic)
|
||||
gvk_barrier(cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, depth, 0, levels, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
let ok = gvk_once_end(render3d_st, cb)
|
||||
gvk_staging_free(render3d_st)
|
||||
return ok
|
||||
|
|
@ -315,8 +321,8 @@ function gvk_tex_grow_mips(render3d_st: mut Render3dState, tex: int, w: int, h:
|
|||
render3d_st.gvk_tex_image[tex] = zero
|
||||
if not gvk_tex_storage(render3d_st, tex, render3d_st.gvk_tex_array[tex] == 1, render3d_st.gvk_tex_glfmt[tex], w, h, layers, true) { return false }
|
||||
let cb = gvk_once_begin(render3d_st)
|
||||
gvk_barrier(cb, old_image, false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[tex], false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, old_image, false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[tex], false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let ic = bytes(VkImageCopy_sizeof)
|
||||
Vk.zero(ic, VkImageCopy_sizeof)
|
||||
Vk.put_i32(ic, VkImageCopy_srcSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
|
|
@ -327,9 +333,11 @@ function gvk_tex_grow_mips(render3d_st: mut Render3dState, tex: int, w: int, h:
|
|||
Vk.put_i32(ic, VkImageCopy_extent + VkExtent3D_height, h)
|
||||
Vk.put_i32(ic, VkImageCopy_extent + VkExtent3D_depth, 1)
|
||||
Vk.cmd_copy_image(cb, old_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, render3d_st.gvk_tex_image[tex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ic)
|
||||
gvk_barrier(cb, render3d_st.gvk_tex_image[tex], false, 0, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[tex], false, 0, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
let ok = gvk_once_end(render3d_st, cb)
|
||||
render3d_st.gvk_mk_x_view += 1
|
||||
Vk.destroy_image_view(render3d_st.gvk_dev, old_view, null)
|
||||
render3d_st.gvk_mk_x_img += 1
|
||||
Vk.destroy_image(render3d_st.gvk_dev, old_image, null)
|
||||
gvk_mem_free(render3d_st, gvk_mem_id(old_mem))
|
||||
return ok
|
||||
|
|
@ -346,7 +354,7 @@ function gvk_tex_mips(render3d_st: mut Render3dState, tex: int, w: int, h: int)
|
|||
return gvk_once_end(render3d_st, cb)
|
||||
}
|
||||
# the chain's blits and barriers recorded into cb (the frame's own, when one is open)
|
||||
function gvk_tex_mips_into(render3d_st: Render3dState, cb: pointer, tex: int, w: int, h: int) -> void {
|
||||
function gvk_tex_mips_into(render3d_st: mut Render3dState, cb: pointer, tex: int, w: int, h: int) -> void {
|
||||
let levels = render3d_st.gvk_tex_levels[tex]
|
||||
if levels <= 1 { return }
|
||||
let image = render3d_st.gvk_tex_image[tex]
|
||||
|
|
@ -358,8 +366,8 @@ function gvk_tex_mips_into(render3d_st: Render3dState, cb: pointer, tex: int, w:
|
|||
if dw < 1 { dw = 1 }
|
||||
var dh = sh / 2
|
||||
if dh < 1 { dh = 1 }
|
||||
gvk_barrier(cb, image, false, lv - 1, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(cb, image, false, lv, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, false, lv - 1, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, false, lv, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
|
||||
let blit = bytes(VkImageBlit_sizeof)
|
||||
Vk.zero(blit, VkImageBlit_sizeof)
|
||||
Vk.put_i32(blit, VkImageBlit_srcSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)
|
||||
|
|
@ -375,8 +383,8 @@ function gvk_tex_mips_into(render3d_st: Render3dState, cb: pointer, tex: int, w:
|
|||
Vk.put_i32(blit, VkImageBlit_dstOffsets + VkOffset3D_sizeof + VkOffset3D_y, dh)
|
||||
Vk.put_i32(blit, VkImageBlit_dstOffsets + VkOffset3D_sizeof + VkOffset3D_z, 1)
|
||||
Vk.cmd_blit_image(cb, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, blit, VK_FILTER_LINEAR)
|
||||
gvk_barrier(cb, image, false, lv - 1, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(cb, image, false, lv, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, false, lv - 1, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, false, lv, 1, layers, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
sw = dw
|
||||
sh = dh
|
||||
}
|
||||
|
|
@ -400,7 +408,7 @@ function gvk_tex_read(render3d_st: mut Render3dState, tex: int, ifmt: int, w: in
|
|||
let image = render3d_st.gvk_tex_image[tex]
|
||||
let depth = gvk_is_depth(ifmt)
|
||||
let cb = gvk_once_begin(render3d_st)
|
||||
gvk_barrier(cb, image, depth, 0, 1, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, depth, 0, 1, 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
|
||||
let bic = bytes(VkBufferImageCopy_sizeof)
|
||||
Vk.zero(bic, VkBufferImageCopy_sizeof)
|
||||
if depth { Vk.put_i32(bic, VkBufferImageCopy_imageSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT) }
|
||||
|
|
@ -410,7 +418,7 @@ function gvk_tex_read(render3d_st: mut Render3dState, tex: int, ifmt: int, w: in
|
|||
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_height, h)
|
||||
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_depth, 1)
|
||||
Vk.cmd_copy_image_to_buffer(cb, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, render3d_st.gvk_st_buf, 1, bic)
|
||||
gvk_barrier(cb, image, depth, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
gvk_barrier(render3d_st, cb, image, depth, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
let ok = gvk_once_end(render3d_st, cb)
|
||||
if ok and cwant == cout { mem_copy(out, src, n) }
|
||||
if ok and cwant < cout {
|
||||
|
|
@ -426,14 +434,39 @@ function gvk_tex_release(render3d_st: mut Render3dState, tex: int) -> void {
|
|||
gvk_frame_wait(render3d_st) # the frame in flight may still read it
|
||||
if render3d_st.gvk_tex_image[tex] == 0 { return }
|
||||
let zero: long = 0
|
||||
render3d_st.gvk_mk_x_view += 1
|
||||
Vk.destroy_image_view(render3d_st.gvk_dev, render3d_st.gvk_tex_view[tex], null)
|
||||
render3d_st.gvk_mk_x_img += 1
|
||||
Vk.destroy_image(render3d_st.gvk_dev, render3d_st.gvk_tex_image[tex], null)
|
||||
gvk_mem_free(render3d_st, gvk_mem_id(render3d_st.gvk_tex_mem[tex]))
|
||||
gvk_layer_views_drop(render3d_st, tex)
|
||||
render3d_st.gvk_tex_image[tex] = zero; render3d_st.gvk_tex_view[tex] = zero; render3d_st.gvk_tex_mem[tex] = zero
|
||||
render3d_st.gvk_tex_levels[tex] = 0; render3d_st.gvk_tex_layers[tex] = 0; render3d_st.gvk_tex_vkfmt[tex] = 0
|
||||
render3d_st.gvk_tex_gen[tex] = render3d_st.gvk_tex_gen[tex] + 1
|
||||
}
|
||||
|
||||
# the per-level and per-layer views gvk_view_of made of a texture go with it: kept, each held its
|
||||
# old Metal texture alive, so every rebuild of the screen targets left the last set's memory behind
|
||||
function gvk_layer_views_drop(render3d_st: mut Render3dState, tex: int) -> void {
|
||||
if render3d_st.gvk_layer_views == null { return }
|
||||
let keys = render3d_st.gvk_layer_views
|
||||
let views = render3d_st.gvk_layer_view
|
||||
let texs = render3d_st.gvk_layer_view_tex
|
||||
var w = 0
|
||||
for i in 0 .. len(keys) {
|
||||
if texs[i] == tex {
|
||||
render3d_st.gvk_mk_x_view += 1
|
||||
Vk.destroy_image_view(render3d_st.gvk_dev, views[i], null)
|
||||
} else {
|
||||
keys[w] = keys[i]; views[w] = views[i]; texs[w] = texs[i]
|
||||
w += 1
|
||||
}
|
||||
}
|
||||
while len(keys) > w { List.pop(keys) }
|
||||
while len(views) > w { List.pop(views) }
|
||||
while len(texs) > w { List.pop(texs) }
|
||||
}
|
||||
|
||||
# ---- samplers -----------------------------------------------------------------------------
|
||||
# One VkSampler per distinct way of reading a texture, made the first time it is asked for.
|
||||
# The arguments are what the renderer set through gpu_tex_param (0 where it set nothing, which
|
||||
|
|
@ -526,6 +559,7 @@ function gvk_sampler(render3d_st: mut Render3dState, min_f: int, mag_f: int, wra
|
|||
Vk.put_i32(sci, VkSamplerCreateInfo_borderColor, VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE)
|
||||
let out = bytes(8)
|
||||
let zero: long = 0
|
||||
render3d_st.gvk_mk_smp += 1
|
||||
let r = Vk.create_sampler(render3d_st.gvk_dev, sci, null, out)
|
||||
if r != VK_SUCCESS { gvk_fail(render3d_st, "vkCreateSampler", r); return zero }
|
||||
let s = gvk_handle(out)
|
||||
|
|
@ -564,6 +598,7 @@ function gvk_buf_release(render3d_st: mut Render3dState, b: int) -> void {
|
|||
while len(render3d_st.gvk_retired_frame) < len(render3d_st.gvk_retired_buf) - 1 { push(render3d_st.gvk_retired_frame, 0) }
|
||||
push(render3d_st.gvk_retired_frame, render3d_st.gvk_buf_used[b])
|
||||
} else {
|
||||
render3d_st.gvk_mk_x_buf += 1
|
||||
Vk.destroy_buffer(render3d_st.gvk_dev, render3d_st.gvk_buf[b], null)
|
||||
gvk_mem_free(render3d_st, gvk_mem_id(render3d_st.gvk_buf_mem[b]))
|
||||
}
|
||||
|
|
@ -582,22 +617,27 @@ function gvk_retire_flush(render3d_st: mut Render3dState) -> void { gvk_retire_u
|
|||
# the frame being recorded read stays
|
||||
function gvk_retire_upto(render3d_st: mut Render3dState, done: int) -> void {
|
||||
if render3d_st.gvk_retired_buf == null { return }
|
||||
let keep_buf = new []long
|
||||
let keep_mem = new []long
|
||||
let keep_frame = new []int
|
||||
if render3d_st.gvk_retired_frame == null { render3d_st.gvk_retired_frame = new []int }
|
||||
while len(render3d_st.gvk_retired_frame) < len(render3d_st.gvk_retired_buf) { push(render3d_st.gvk_retired_frame, 0) }
|
||||
# compacted in place: three fresh lists a frame were never given back
|
||||
var w = 0
|
||||
for i in 0 .. len(render3d_st.gvk_retired_buf) {
|
||||
var f = 0
|
||||
if render3d_st.gvk_retired_frame != null and i < len(render3d_st.gvk_retired_frame) { f = render3d_st.gvk_retired_frame[i] }
|
||||
let f = render3d_st.gvk_retired_frame[i]
|
||||
if f > done {
|
||||
push(keep_buf, render3d_st.gvk_retired_buf[i]); push(keep_mem, render3d_st.gvk_retired_mem[i]); push(keep_frame, f)
|
||||
render3d_st.gvk_retired_buf[w] = render3d_st.gvk_retired_buf[i]; render3d_st.gvk_retired_mem[w] = render3d_st.gvk_retired_mem[i]; render3d_st.gvk_retired_frame[w] = f
|
||||
w += 1
|
||||
} else {
|
||||
render3d_st.gvk_mk_x_buf += 1
|
||||
Vk.destroy_buffer(render3d_st.gvk_dev, render3d_st.gvk_retired_buf[i], null)
|
||||
gvk_mem_free(render3d_st, gvk_mem_id(render3d_st.gvk_retired_mem[i]))
|
||||
}
|
||||
}
|
||||
render3d_st.gvk_retired_buf = keep_buf
|
||||
render3d_st.gvk_retired_mem = keep_mem
|
||||
render3d_st.gvk_retired_frame = keep_frame
|
||||
let rb = render3d_st.gvk_retired_buf
|
||||
let rm = render3d_st.gvk_retired_mem
|
||||
let rf = render3d_st.gvk_retired_frame
|
||||
while len(rb) > w { List.pop(rb) }
|
||||
while len(rm) > w { List.pop(rm) }
|
||||
while len(rf) > w { List.pop(rf) }
|
||||
}
|
||||
|
||||
# A buffer a compute pass writes: a draw later in the same frame reads what the GPU put there,
|
||||
|
|
@ -626,6 +666,7 @@ function gvk_buf_reserve(render3d_st: mut Render3dState, b: int, n: int) -> bool
|
|||
Vk.put_i32(bci, VkBufferCreateInfo_usage, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
|
||||
Vk.put_i32(bci, VkBufferCreateInfo_sharingMode, VK_SHARING_MODE_EXCLUSIVE)
|
||||
let out = bytes(8)
|
||||
render3d_st.gvk_mk_buf += 1
|
||||
var r = Vk.create_buffer(render3d_st.gvk_dev, bci, null, out)
|
||||
if r != VK_SUCCESS { return gvk_fail(render3d_st, `vkCreateBuffer ({size} bytes)`, r) }
|
||||
let buf = gvk_handle(out)
|
||||
|
|
|
|||
|
|
@ -102,9 +102,14 @@ function gg_cull_frame(render3d_st: mut Render3dState) -> void {
|
|||
gg_tiles(render3d_st, 4, 0.0, 16.0)
|
||||
gg_tiles(render3d_st, 8, 16.0, 40.0)
|
||||
gg_tiles(render3d_st, 16, 40.0, render3d_st.grass_radius)
|
||||
let rb = words(4)
|
||||
# made once: a words() a frame is a calloc nothing frees
|
||||
if render3d_st.gg_rb == null {
|
||||
render3d_st.gg_rb = words(4); render3d_st.gg_cb = words(1); render3d_st.gg_bufs = words(3)
|
||||
render3d_st.gg_texs = words(2); render3d_st.gg_pr = words(48)
|
||||
}
|
||||
let rb = render3d_st.gg_rb
|
||||
rb[0] = GG_BANDS; rb[1] = 0; rb[2] = 0; rb[3] = 0
|
||||
let cb = words(1)
|
||||
let cb = render3d_st.gg_cb
|
||||
cb[0] = render3d_st.gg_cmds
|
||||
gpu_dispatch(render3d_st, render3d_st.gg_reset, data_of(rb), 16, cb, 1)
|
||||
if render3d_st.gg_n == 0 { return }
|
||||
|
|
@ -112,16 +117,16 @@ function gg_cull_frame(render3d_st: mut Render3dState) -> void {
|
|||
let tb = render3d_st.gg_tiles_buf[render3d_st.r3d_test_frame % 2]
|
||||
gpu_buffer_upload(render3d_st, tb, render3d_st.gg_n * 16, data_of(render3d_st.gg_tv), GPU_DYNAMIC)
|
||||
let pr = gg_params(render3d_st)
|
||||
let bufs = words(3)
|
||||
let bufs = render3d_st.gg_bufs
|
||||
bufs[0] = tb; bufs[1] = render3d_st.gg_out; bufs[2] = render3d_st.gg_cmds
|
||||
let texs = words(2)
|
||||
let texs = render3d_st.gg_texs
|
||||
texs[0] = render3d_st.ter_height_tex; texs[1] = render3d_st.ter_ortho_tex
|
||||
gpu_dispatch_tex(render3d_st, render3d_st.gg_cull, data_of(pr), 192, bufs, texs, (render3d_st.gg_max + 63) / 64, render3d_st.gg_n)
|
||||
}
|
||||
|
||||
# grass_cull.comp's Params, std140: 12 vec4s
|
||||
function gg_params(render3d_st: Render3dState) -> words {
|
||||
let pr = words(48)
|
||||
# grass_cull.comp's Params, std140: 12 vec4s, into the block made once in gg_cull_frame
|
||||
function gg_params(render3d_st: mut Render3dState) -> words {
|
||||
let pr = render3d_st.gg_pr
|
||||
for i in 0 .. 48 { pr[i] = 0 }
|
||||
if render3d_st.cam_planes != null { for i in 0 .. 16 { pr[i] = float_bits(render3d_st.cam_planes[i]) } }
|
||||
pr[16] = float_bits(render3d_st.cam_pos[0]); pr[17] = float_bits(render3d_st.cam_pos[1]); pr[18] = float_bits(render3d_st.cam_pos[2]); pr[19] = float_bits(render3d_st.grass_radius)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ vec3 bladeField(vec2 xz, float y) {
|
|||
// dry and green patches a few metres across, and the tussocks' own shade of the same green
|
||||
float dryp = smoothstep(0.2, 0.8, gnoise(xz * 0.33 + 17.0) * 0.5 + 0.5);
|
||||
t *= mix(vec3(0.92, 1.0, 0.95), vec3(1.30, 1.10, 0.62), dryp);
|
||||
return t * (0.72 + 0.56 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
|
||||
return t * (0.55 + 0.80 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ vec3 bladeField(vec2 xz, float y) {
|
|||
t *= mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy);
|
||||
float dryp = smoothstep(0.2, 0.8, gnoise(xz * 0.33 + 17.0) * 0.5 + 0.5);
|
||||
t *= mix(vec3(0.92, 1.0, 0.95), vec3(1.30, 1.10, 0.62), dryp);
|
||||
return t * (0.72 + 0.56 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
|
||||
return t * (0.55 + 0.80 * (gnoise(xz * 1.9 + 41.0) * 0.5 + 0.5));
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
|
@ -118,6 +118,13 @@ void main() {
|
|||
uint o = (pr.base[b] + slot) * 4u;
|
||||
outv[o] = vec4(xz.x, h - 0.02, xz.y, seed);
|
||||
outv[o + 1u] = vec4(sin(ang), cos(ang), tall, bw);
|
||||
outv[o + 2u] = vec4(bladeField(xz, h), 0.6 + 0.8 * h4);
|
||||
// each blade its own: a hue a little toward olive or toward blue-green, and in a dry patch more
|
||||
// of them gone to straw - a meadow is mixed blade by blade, not tinted as one
|
||||
vec3 field = bladeField(xz, h);
|
||||
float hj = bladeHash(ci, j, 7) - 0.5;
|
||||
field *= vec3(1.0 + 0.30 * hj, 1.0, 1.0 - 0.30 * hj);
|
||||
float dryp = smoothstep(0.2, 0.8, gnoise(xz * 0.33 + 17.0) * 0.5 + 0.5);
|
||||
if (bladeHash(ci, j, 8) < 0.10 + 0.45 * dryp) field *= vec3(1.45, 1.18, 0.52);
|
||||
outv[o + 2u] = vec4(field, 0.6 + 0.8 * h4);
|
||||
outv[o + 3u] = vec4(gn, dist);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,9 @@ void main() {
|
|||
// an occlusion term; grass albedo is capped near 0.5 and this was dividing it by five.
|
||||
// A blade is a thin thing standing in open air: shaded at the root by its neighbours,
|
||||
// not buried.
|
||||
arm = vec3(mix(0.55, 1.0, t), 0.85, 0.0);
|
||||
// the inside of a sward is its own shade: a blade's base sits among its neighbours (the old clumps
|
||||
// got this from the shadow maps, at 4.5 ms; seen from above it is most of a meadow's texture)
|
||||
arm = vec3(mix(0.30, 1.0, smoothstep(0.0, 0.8, t)), 0.85, 0.0);
|
||||
#elif defined(CARD)
|
||||
// thin grass is lit from either side: face the card toward the sun before shading
|
||||
if (dot(N, u_sun_dir) < 0.0) N = -N;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -2996,10 +2996,11 @@ U 2e2908c8 frag u_half 828 float 1 0
|
|||
U 2e2908c8 frag u_texel 832 float 1 0
|
||||
U 2e2908c8 frag u_ortho_on 836 float 1 0
|
||||
U 2e2908c8 frag u_carpet_on 840 float 1 0
|
||||
U 2e2908c8 frag u_snow_line 844 float 1 0
|
||||
U 2e2908c8 frag u_lake_level 848 float 1 0
|
||||
U 2e2908c8 frag u_wet 852 float 1 0
|
||||
U 2e2908c8 frag u_sea_level 856 float 1 0
|
||||
U 2e2908c8 frag u_grass_reach 844 float 1 0
|
||||
U 2e2908c8 frag u_snow_line 848 float 1 0
|
||||
U 2e2908c8 frag u_lake_level 852 float 1 0
|
||||
U 2e2908c8 frag u_wet 856 float 1 0
|
||||
U 2e2908c8 frag u_sea_level 860 float 1 0
|
||||
U 2e2908c8 frag u_lake 864 vec4 1 0
|
||||
U 2e2908c8 frag u_origin 880 vec2 1 0
|
||||
U 2e2908c8 frag u_view 896 mat4 1 0
|
||||
|
|
@ -3073,10 +3074,11 @@ U 1f95f31b frag u_half 828 float 1 0
|
|||
U 1f95f31b frag u_texel 832 float 1 0
|
||||
U 1f95f31b frag u_ortho_on 836 float 1 0
|
||||
U 1f95f31b frag u_carpet_on 840 float 1 0
|
||||
U 1f95f31b frag u_snow_line 844 float 1 0
|
||||
U 1f95f31b frag u_lake_level 848 float 1 0
|
||||
U 1f95f31b frag u_wet 852 float 1 0
|
||||
U 1f95f31b frag u_sea_level 856 float 1 0
|
||||
U 1f95f31b frag u_grass_reach 844 float 1 0
|
||||
U 1f95f31b frag u_snow_line 848 float 1 0
|
||||
U 1f95f31b frag u_lake_level 852 float 1 0
|
||||
U 1f95f31b frag u_wet 856 float 1 0
|
||||
U 1f95f31b frag u_sea_level 860 float 1 0
|
||||
U 1f95f31b frag u_lake 864 vec4 1 0
|
||||
U 1f95f31b frag u_origin 880 vec2 1 0
|
||||
U 1f95f31b frag u_view 896 mat4 1 0
|
||||
|
|
@ -3150,10 +3152,11 @@ U f4382918 frag u_half 828 float 1 0
|
|||
U f4382918 frag u_texel 832 float 1 0
|
||||
U f4382918 frag u_ortho_on 836 float 1 0
|
||||
U f4382918 frag u_carpet_on 840 float 1 0
|
||||
U f4382918 frag u_snow_line 844 float 1 0
|
||||
U f4382918 frag u_lake_level 848 float 1 0
|
||||
U f4382918 frag u_wet 852 float 1 0
|
||||
U f4382918 frag u_sea_level 856 float 1 0
|
||||
U f4382918 frag u_grass_reach 844 float 1 0
|
||||
U f4382918 frag u_snow_line 848 float 1 0
|
||||
U f4382918 frag u_lake_level 852 float 1 0
|
||||
U f4382918 frag u_wet 856 float 1 0
|
||||
U f4382918 frag u_sea_level 860 float 1 0
|
||||
U f4382918 frag u_lake 864 vec4 1 0
|
||||
U f4382918 frag u_origin 880 vec2 1 0
|
||||
U f4382918 frag u_view 896 mat4 1 0
|
||||
|
|
@ -3227,10 +3230,11 @@ U f2952361 frag u_half 828 float 1 0
|
|||
U f2952361 frag u_texel 832 float 1 0
|
||||
U f2952361 frag u_ortho_on 836 float 1 0
|
||||
U f2952361 frag u_carpet_on 840 float 1 0
|
||||
U f2952361 frag u_snow_line 844 float 1 0
|
||||
U f2952361 frag u_lake_level 848 float 1 0
|
||||
U f2952361 frag u_wet 852 float 1 0
|
||||
U f2952361 frag u_sea_level 856 float 1 0
|
||||
U f2952361 frag u_grass_reach 844 float 1 0
|
||||
U f2952361 frag u_snow_line 848 float 1 0
|
||||
U f2952361 frag u_lake_level 852 float 1 0
|
||||
U f2952361 frag u_wet 856 float 1 0
|
||||
U f2952361 frag u_sea_level 860 float 1 0
|
||||
U f2952361 frag u_lake 864 vec4 1 0
|
||||
U f2952361 frag u_origin 880 vec2 1 0
|
||||
U f2952361 frag u_view 896 mat4 1 0
|
||||
|
|
@ -3304,10 +3308,11 @@ U a0f2dbac frag u_half 828 float 1 0
|
|||
U a0f2dbac frag u_texel 832 float 1 0
|
||||
U a0f2dbac frag u_ortho_on 836 float 1 0
|
||||
U a0f2dbac frag u_carpet_on 840 float 1 0
|
||||
U a0f2dbac frag u_snow_line 844 float 1 0
|
||||
U a0f2dbac frag u_lake_level 848 float 1 0
|
||||
U a0f2dbac frag u_wet 852 float 1 0
|
||||
U a0f2dbac frag u_sea_level 856 float 1 0
|
||||
U a0f2dbac frag u_grass_reach 844 float 1 0
|
||||
U a0f2dbac frag u_snow_line 848 float 1 0
|
||||
U a0f2dbac frag u_lake_level 852 float 1 0
|
||||
U a0f2dbac frag u_wet 856 float 1 0
|
||||
U a0f2dbac frag u_sea_level 860 float 1 0
|
||||
U a0f2dbac frag u_lake 864 vec4 1 0
|
||||
U a0f2dbac frag u_origin 880 vec2 1 0
|
||||
U a0f2dbac frag u_view 896 mat4 1 0
|
||||
|
|
@ -3381,10 +3386,11 @@ U 5e4589a1 frag u_half 828 float 1 0
|
|||
U 5e4589a1 frag u_texel 832 float 1 0
|
||||
U 5e4589a1 frag u_ortho_on 836 float 1 0
|
||||
U 5e4589a1 frag u_carpet_on 840 float 1 0
|
||||
U 5e4589a1 frag u_snow_line 844 float 1 0
|
||||
U 5e4589a1 frag u_lake_level 848 float 1 0
|
||||
U 5e4589a1 frag u_wet 852 float 1 0
|
||||
U 5e4589a1 frag u_sea_level 856 float 1 0
|
||||
U 5e4589a1 frag u_grass_reach 844 float 1 0
|
||||
U 5e4589a1 frag u_snow_line 848 float 1 0
|
||||
U 5e4589a1 frag u_lake_level 852 float 1 0
|
||||
U 5e4589a1 frag u_wet 856 float 1 0
|
||||
U 5e4589a1 frag u_sea_level 860 float 1 0
|
||||
U 5e4589a1 frag u_lake 864 vec4 1 0
|
||||
U 5e4589a1 frag u_origin 880 vec2 1 0
|
||||
U 5e4589a1 frag u_view 896 mat4 1 0
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ uniform float u_ortho_on;
|
|||
uniform sampler2D u_rock_d; uniform sampler2D u_rock_n; uniform sampler2D u_rock_a;
|
||||
uniform sampler2D u_snow_d; uniform sampler2D u_carpet; // the clump cards baked straight down (alpha = coverage)
|
||||
uniform float u_carpet_on;
|
||||
uniform float u_grass_reach; // where the GPU blades stop (0: none): the ground under them is in their shade
|
||||
uniform float u_snow_line;
|
||||
uniform float u_lake_level; // the ground just above the water is wet and dark
|
||||
// ---- RAIN THAT LEAVES SOMETHING BEHIND -----------------------------------------------------
|
||||
|
|
@ -339,6 +340,18 @@ vec3 groundShade(vec3 p, vec3 N, float slope, float dist, float viewDepth, bool
|
|||
vec3 cc = cp.rgb * vec3(0.5, 0.57, 0.45) * mix(vec3(0.85, 0.92, 0.9), vec3(1.1, 1.05, 0.85), smoothstep(-0.35, 0.35, N.z)) * (0.75 + 0.35 * lush);
|
||||
gA = mix(gA, cc, max(cp.a, 0.35) * carpetW * 0.97);
|
||||
}
|
||||
// The blades' own patches (grass_cull.comp's bladeField): patchiness and dry patches, so where
|
||||
// the blades thin out the ground they stand on carries the same meadow, not a lawn
|
||||
{
|
||||
float patchy = fbmC(cheap, p.xz * 0.045, 3) * 0.5 + 0.5;
|
||||
float dryp = smoothstep(0.2, 0.8, gnoise(p.xz * 0.33 + 17.0) * 0.5 + 0.5);
|
||||
vec3 pf = mix(vec3(0.7, 0.8, 0.55), vec3(1.1, 1.05, 0.85), patchy) * mix(vec3(0.92, 1.0, 0.95), vec3(1.30, 1.10, 0.62), dryp);
|
||||
// and the tussocks' own shade, half a metre across: where blades stand a pixel wide the ground
|
||||
// is most of what shows, and it has to carry the same light and dark as the blades on it
|
||||
float tus = 0.55 + 0.80 * (gnoise(p.xz * 1.9 + 41.0) * 0.5 + 0.5);
|
||||
gA *= mix(vec3(1.0), pf / vec3(0.95, 0.96, 0.72) * tus, grassW);
|
||||
if (u_grass_reach > 0.0) gA *= mix(1.0, mix(0.50, 1.0, smoothstep(u_grass_reach * 0.25, u_grass_reach, dist)), grassW);
|
||||
}
|
||||
// Subalpine forest floor: dark duff where the stands are dense. The photograph-driven
|
||||
// term marks duff only where the survey actually shows dense conifer, and is the same
|
||||
// at any distance — ground shading must not depend on where the viewer is.
|
||||
|
|
|
|||
|
|
@ -418,6 +418,9 @@ function terrain_bind_prog(render3d_st: mut Render3dState, p: int) -> void {
|
|||
r3d_bind_2d(render3d_st, p, "u_snow_d", 10, render3d_st.ter_tex[9])
|
||||
if render3d_st.ter_carpet != 0 { r3d_bind_2d(render3d_st, p, "u_carpet", 11, render3d_st.ter_carpet); u_f(render3d_st, gpu_uniform(render3d_st, p, "u_carpet_on"), 1.0) }
|
||||
else { r3d_bind_2d(render3d_st, p, "u_carpet", 11, render3d_st.ter_tex[0]); u_f(render3d_st, gpu_uniform(render3d_st, p, "u_carpet_on"), 0.0) }
|
||||
var reach = 0.0
|
||||
if grass_live(render3d_st) { reach = render3d_st.grass_radius }
|
||||
u_f(render3d_st, gpu_uniform(render3d_st, p, "u_grass_reach"), reach)
|
||||
u_f(render3d_st, gpu_uniform(render3d_st, p, "u_half"), float(render3d_st.TERRAIN_HALF))
|
||||
u_f(render3d_st, gpu_uniform(render3d_st, p, "u_texel"), 1.0 / float(TERRAIN_RES))
|
||||
u_f(render3d_st, gpu_uniform(render3d_st, p, "u_snow_line"), render3d_st.ter_snow_line)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue