xref: /third_party/mesa3d/src/virtio/vulkan/vn_cs.c (revision bf215546)
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