1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2019 Google LLC 3bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT 4bf215546Sopenharmony_ci */ 5bf215546Sopenharmony_ci 6bf215546Sopenharmony_ci#include "vn_cs.h" 7bf215546Sopenharmony_ci 8bf215546Sopenharmony_ci#include "vn_instance.h" 9bf215546Sopenharmony_ci#include "vn_renderer.h" 10bf215546Sopenharmony_ci 11bf215546Sopenharmony_cistruct vn_cs_renderer_protocol_info _vn_cs_renderer_protocol_info = { 12bf215546Sopenharmony_ci .mutex = _SIMPLE_MTX_INITIALIZER_NP, 13bf215546Sopenharmony_ci}; 14bf215546Sopenharmony_ci 15bf215546Sopenharmony_cistatic void 16bf215546Sopenharmony_civn_cs_renderer_protocol_info_init_once(struct vn_instance *instance) 17bf215546Sopenharmony_ci{ 18bf215546Sopenharmony_ci const struct vn_renderer_info *renderer_info = &instance->renderer->info; 19bf215546Sopenharmony_ci /* assume renderer protocol supports all extensions if bit 0 is not set */ 20bf215546Sopenharmony_ci const bool support_all_exts = 21bf215546Sopenharmony_ci !vn_info_extension_mask_test(renderer_info->vk_extension_mask, 0); 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci _vn_cs_renderer_protocol_info.api_version = renderer_info->vk_xml_version; 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci STATIC_ASSERT(sizeof(renderer_info->vk_extension_mask) >= 26bf215546Sopenharmony_ci sizeof(_vn_cs_renderer_protocol_info.extension_bitset)); 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci for (uint32_t i = 1; i <= VN_INFO_EXTENSION_MAX_NUMBER; i++) { 29bf215546Sopenharmony_ci /* use protocl helper to ensure mask decoding matches encoding */ 30bf215546Sopenharmony_ci if (support_all_exts || 31bf215546Sopenharmony_ci vn_info_extension_mask_test(renderer_info->vk_extension_mask, i)) 32bf215546Sopenharmony_ci BITSET_SET(_vn_cs_renderer_protocol_info.extension_bitset, i); 33bf215546Sopenharmony_ci } 34bf215546Sopenharmony_ci} 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_civoid 37bf215546Sopenharmony_civn_cs_renderer_protocol_info_init(struct vn_instance *instance) 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci simple_mtx_lock(&_vn_cs_renderer_protocol_info.mutex); 40bf215546Sopenharmony_ci if (_vn_cs_renderer_protocol_info.init_once) { 41bf215546Sopenharmony_ci simple_mtx_unlock(&_vn_cs_renderer_protocol_info.mutex); 42bf215546Sopenharmony_ci return; 43bf215546Sopenharmony_ci } 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci vn_cs_renderer_protocol_info_init_once(instance); 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci _vn_cs_renderer_protocol_info.init_once = true; 48bf215546Sopenharmony_ci simple_mtx_unlock(&_vn_cs_renderer_protocol_info.mutex); 49bf215546Sopenharmony_ci} 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_cistatic void 52bf215546Sopenharmony_civn_cs_encoder_sanity_check(struct vn_cs_encoder *enc) 53bf215546Sopenharmony_ci{ 54bf215546Sopenharmony_ci assert(enc->buffer_count <= enc->buffer_max); 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci size_t total_committed_size = 0; 57bf215546Sopenharmony_ci for (uint32_t i = 0; i < enc->buffer_count; i++) 58bf215546Sopenharmony_ci total_committed_size += enc->buffers[i].committed_size; 59bf215546Sopenharmony_ci assert(enc->total_committed_size == total_committed_size); 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci if (enc->buffer_count) { 62bf215546Sopenharmony_ci const struct vn_cs_encoder_buffer *cur_buf = 63bf215546Sopenharmony_ci &enc->buffers[enc->buffer_count - 1]; 64bf215546Sopenharmony_ci assert(cur_buf->base <= enc->cur && enc->cur <= enc->end && 65bf215546Sopenharmony_ci enc->end <= cur_buf->base + enc->current_buffer_size); 66bf215546Sopenharmony_ci if (cur_buf->committed_size) 67bf215546Sopenharmony_ci assert(enc->cur == enc->end); 68bf215546Sopenharmony_ci } else { 69bf215546Sopenharmony_ci assert(!enc->current_buffer_size); 70bf215546Sopenharmony_ci assert(!enc->cur && !enc->end); 71bf215546Sopenharmony_ci } 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cistatic void 75bf215546Sopenharmony_civn_cs_encoder_add_buffer(struct vn_cs_encoder *enc, 76bf215546Sopenharmony_ci struct vn_renderer_shmem *shmem, 77bf215546Sopenharmony_ci size_t offset, 78bf215546Sopenharmony_ci void *base, 79bf215546Sopenharmony_ci size_t size) 80bf215546Sopenharmony_ci{ 81bf215546Sopenharmony_ci /* add a buffer and make it current */ 82bf215546Sopenharmony_ci assert(enc->buffer_count < enc->buffer_max); 83bf215546Sopenharmony_ci struct vn_cs_encoder_buffer *cur_buf = &enc->buffers[enc->buffer_count++]; 84bf215546Sopenharmony_ci /* shmem ownership transferred */ 85bf215546Sopenharmony_ci cur_buf->shmem = shmem; 86bf215546Sopenharmony_ci cur_buf->offset = offset; 87bf215546Sopenharmony_ci cur_buf->base = base; 88bf215546Sopenharmony_ci cur_buf->committed_size = 0; 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci /* update the write pointer */ 91bf215546Sopenharmony_ci enc->cur = base; 92bf215546Sopenharmony_ci enc->end = base + size; 93bf215546Sopenharmony_ci} 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_cistatic void 96bf215546Sopenharmony_civn_cs_encoder_commit_buffer(struct vn_cs_encoder *enc) 97bf215546Sopenharmony_ci{ 98bf215546Sopenharmony_ci assert(enc->buffer_count); 99bf215546Sopenharmony_ci struct vn_cs_encoder_buffer *cur_buf = 100bf215546Sopenharmony_ci &enc->buffers[enc->buffer_count - 1]; 101bf215546Sopenharmony_ci const size_t written_size = enc->cur - cur_buf->base; 102bf215546Sopenharmony_ci if (cur_buf->committed_size) { 103bf215546Sopenharmony_ci assert(cur_buf->committed_size == written_size); 104bf215546Sopenharmony_ci } else { 105bf215546Sopenharmony_ci cur_buf->committed_size = written_size; 106bf215546Sopenharmony_ci enc->total_committed_size += written_size; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci} 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_cistatic void 111bf215546Sopenharmony_civn_cs_encoder_gc_buffers(struct vn_cs_encoder *enc) 112bf215546Sopenharmony_ci{ 113bf215546Sopenharmony_ci /* when the shmem pool is used, no need to cache the shmem in cs */ 114bf215546Sopenharmony_ci if (enc->storage_type == VN_CS_ENCODER_STORAGE_SHMEM_POOL) { 115bf215546Sopenharmony_ci for (uint32_t i = 0; i < enc->buffer_count; i++) { 116bf215546Sopenharmony_ci vn_renderer_shmem_unref(enc->instance->renderer, 117bf215546Sopenharmony_ci enc->buffers[i].shmem); 118bf215546Sopenharmony_ci } 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci enc->buffer_count = 0; 121bf215546Sopenharmony_ci enc->total_committed_size = 0; 122bf215546Sopenharmony_ci enc->current_buffer_size = 0; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci enc->cur = NULL; 125bf215546Sopenharmony_ci enc->end = NULL; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci return; 128bf215546Sopenharmony_ci } 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci /* free all but the current buffer */ 131bf215546Sopenharmony_ci assert(enc->buffer_count); 132bf215546Sopenharmony_ci struct vn_cs_encoder_buffer *cur_buf = 133bf215546Sopenharmony_ci &enc->buffers[enc->buffer_count - 1]; 134bf215546Sopenharmony_ci for (uint32_t i = 0; i < enc->buffer_count - 1; i++) 135bf215546Sopenharmony_ci vn_renderer_shmem_unref(enc->instance->renderer, enc->buffers[i].shmem); 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci /* move the current buffer to the beginning, skipping the used part */ 138bf215546Sopenharmony_ci const size_t used = cur_buf->offset + cur_buf->committed_size; 139bf215546Sopenharmony_ci enc->buffer_count = 0; 140bf215546Sopenharmony_ci vn_cs_encoder_add_buffer(enc, cur_buf->shmem, used, 141bf215546Sopenharmony_ci cur_buf->base + cur_buf->committed_size, 142bf215546Sopenharmony_ci enc->current_buffer_size - used); 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci enc->total_committed_size = 0; 145bf215546Sopenharmony_ci} 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_civoid 148bf215546Sopenharmony_civn_cs_encoder_init(struct vn_cs_encoder *enc, 149bf215546Sopenharmony_ci struct vn_instance *instance, 150bf215546Sopenharmony_ci enum vn_cs_encoder_storage_type storage_type, 151bf215546Sopenharmony_ci size_t min_size) 152bf215546Sopenharmony_ci{ 153bf215546Sopenharmony_ci /* VN_CS_ENCODER_INITIALIZER* should be used instead */ 154bf215546Sopenharmony_ci assert(storage_type != VN_CS_ENCODER_STORAGE_POINTER); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci memset(enc, 0, sizeof(*enc)); 157bf215546Sopenharmony_ci enc->instance = instance; 158bf215546Sopenharmony_ci enc->storage_type = storage_type; 159bf215546Sopenharmony_ci enc->min_buffer_size = min_size; 160bf215546Sopenharmony_ci} 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_civoid 163bf215546Sopenharmony_civn_cs_encoder_fini(struct vn_cs_encoder *enc) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci if (unlikely(enc->storage_type == VN_CS_ENCODER_STORAGE_POINTER)) 166bf215546Sopenharmony_ci return; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci for (uint32_t i = 0; i < enc->buffer_count; i++) 169bf215546Sopenharmony_ci vn_renderer_shmem_unref(enc->instance->renderer, enc->buffers[i].shmem); 170bf215546Sopenharmony_ci if (enc->buffers) 171bf215546Sopenharmony_ci free(enc->buffers); 172bf215546Sopenharmony_ci} 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci/** 175bf215546Sopenharmony_ci * Reset a cs for reuse. 176bf215546Sopenharmony_ci */ 177bf215546Sopenharmony_civoid 178bf215546Sopenharmony_civn_cs_encoder_reset(struct vn_cs_encoder *enc) 179bf215546Sopenharmony_ci{ 180bf215546Sopenharmony_ci /* enc->error is sticky */ 181bf215546Sopenharmony_ci if (likely(enc->buffer_count)) 182bf215546Sopenharmony_ci vn_cs_encoder_gc_buffers(enc); 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_cistatic uint32_t 186bf215546Sopenharmony_cinext_array_size(uint32_t cur_size, uint32_t min_size) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci const uint32_t next_size = cur_size ? cur_size * 2 : min_size; 189bf215546Sopenharmony_ci return next_size > cur_size ? next_size : 0; 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_cistatic size_t 193bf215546Sopenharmony_cinext_buffer_size(size_t cur_size, size_t min_size, size_t need) 194bf215546Sopenharmony_ci{ 195bf215546Sopenharmony_ci size_t next_size = cur_size ? cur_size * 2 : min_size; 196bf215546Sopenharmony_ci while (next_size < need) { 197bf215546Sopenharmony_ci next_size *= 2; 198bf215546Sopenharmony_ci if (!next_size) 199bf215546Sopenharmony_ci return 0; 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci return next_size; 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_cistatic bool 205bf215546Sopenharmony_civn_cs_encoder_grow_buffer_array(struct vn_cs_encoder *enc) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci const uint32_t buf_max = next_array_size(enc->buffer_max, 4); 208bf215546Sopenharmony_ci if (!buf_max) 209bf215546Sopenharmony_ci return false; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci void *bufs = realloc(enc->buffers, sizeof(*enc->buffers) * buf_max); 212bf215546Sopenharmony_ci if (!bufs) 213bf215546Sopenharmony_ci return false; 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_ci enc->buffers = bufs; 216bf215546Sopenharmony_ci enc->buffer_max = buf_max; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci return true; 219bf215546Sopenharmony_ci} 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci/** 222bf215546Sopenharmony_ci * Add a new vn_cs_encoder_buffer to a cs. 223bf215546Sopenharmony_ci */ 224bf215546Sopenharmony_cibool 225bf215546Sopenharmony_civn_cs_encoder_reserve_internal(struct vn_cs_encoder *enc, size_t size) 226bf215546Sopenharmony_ci{ 227bf215546Sopenharmony_ci VN_TRACE_FUNC(); 228bf215546Sopenharmony_ci if (unlikely(enc->storage_type == VN_CS_ENCODER_STORAGE_POINTER)) 229bf215546Sopenharmony_ci return false; 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci if (enc->buffer_count >= enc->buffer_max) { 232bf215546Sopenharmony_ci if (!vn_cs_encoder_grow_buffer_array(enc)) 233bf215546Sopenharmony_ci return false; 234bf215546Sopenharmony_ci assert(enc->buffer_count < enc->buffer_max); 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci size_t buf_size = 0; 238bf215546Sopenharmony_ci if (likely(enc->buffer_count)) { 239bf215546Sopenharmony_ci vn_cs_encoder_commit_buffer(enc); 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci if (enc->storage_type == VN_CS_ENCODER_STORAGE_SHMEM_ARRAY) { 242bf215546Sopenharmony_ci /* if the current buffer is reused from the last vn_cs_encoder_reset 243bf215546Sopenharmony_ci * (i.e., offset != 0), do not double the size 244bf215546Sopenharmony_ci * 245bf215546Sopenharmony_ci * TODO better strategy to grow buffer size 246bf215546Sopenharmony_ci */ 247bf215546Sopenharmony_ci const struct vn_cs_encoder_buffer *cur_buf = 248bf215546Sopenharmony_ci &enc->buffers[enc->buffer_count - 1]; 249bf215546Sopenharmony_ci if (cur_buf->offset) 250bf215546Sopenharmony_ci buf_size = next_buffer_size(0, enc->current_buffer_size, size); 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci if (!buf_size) { 255bf215546Sopenharmony_ci /* double the size */ 256bf215546Sopenharmony_ci buf_size = next_buffer_size(enc->current_buffer_size, 257bf215546Sopenharmony_ci enc->min_buffer_size, size); 258bf215546Sopenharmony_ci if (!buf_size) 259bf215546Sopenharmony_ci return false; 260bf215546Sopenharmony_ci } 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci struct vn_renderer_shmem *shmem; 263bf215546Sopenharmony_ci size_t buf_offset; 264bf215546Sopenharmony_ci if (enc->storage_type == VN_CS_ENCODER_STORAGE_SHMEM_ARRAY) { 265bf215546Sopenharmony_ci shmem = vn_renderer_shmem_create(enc->instance->renderer, buf_size); 266bf215546Sopenharmony_ci buf_offset = 0; 267bf215546Sopenharmony_ci } else { 268bf215546Sopenharmony_ci assert(enc->storage_type == VN_CS_ENCODER_STORAGE_SHMEM_POOL); 269bf215546Sopenharmony_ci shmem = 270bf215546Sopenharmony_ci vn_instance_cs_shmem_alloc(enc->instance, buf_size, &buf_offset); 271bf215546Sopenharmony_ci } 272bf215546Sopenharmony_ci if (!shmem) 273bf215546Sopenharmony_ci return false; 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci if (unlikely(!enc->instance->renderer->info.supports_blob_id_0)) { 276bf215546Sopenharmony_ci uint32_t roundtrip; 277bf215546Sopenharmony_ci VkResult result = 278bf215546Sopenharmony_ci vn_instance_submit_roundtrip(enc->instance, &roundtrip); 279bf215546Sopenharmony_ci if (result != VK_SUCCESS) { 280bf215546Sopenharmony_ci vn_renderer_shmem_unref(enc->instance->renderer, shmem); 281bf215546Sopenharmony_ci return false; 282bf215546Sopenharmony_ci } 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci enc->current_buffer_roundtrip = roundtrip; 285bf215546Sopenharmony_ci } 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci vn_cs_encoder_add_buffer(enc, shmem, buf_offset, 288bf215546Sopenharmony_ci shmem->mmap_ptr + buf_offset, buf_size); 289bf215546Sopenharmony_ci enc->current_buffer_size = buf_size; 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci vn_cs_encoder_sanity_check(enc); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci return true; 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci/* 297bf215546Sopenharmony_ci * Commit written data. 298bf215546Sopenharmony_ci */ 299bf215546Sopenharmony_civoid 300bf215546Sopenharmony_civn_cs_encoder_commit(struct vn_cs_encoder *enc) 301bf215546Sopenharmony_ci{ 302bf215546Sopenharmony_ci if (likely(enc->buffer_count)) { 303bf215546Sopenharmony_ci vn_cs_encoder_commit_buffer(enc); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci /* trigger the slow path on next vn_cs_encoder_reserve */ 306bf215546Sopenharmony_ci enc->end = enc->cur; 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci vn_cs_encoder_sanity_check(enc); 310bf215546Sopenharmony_ci} 311