1/*
2 * Copyright 2019 Google LLC
3 * SPDX-License-Identifier: MIT
4 */
5
6#ifndef VN_CS_H
7#define VN_CS_H
8
9#include "vn_common.h"
10
11#define VN_CS_ENCODER_BUFFER_INITIALIZER(storage)                            \
12   (struct vn_cs_encoder_buffer) { .base = storage, }
13
14/* note that buffers points to an unamed local variable */
15#define VN_CS_ENCODER_INITIALIZER_LOCAL(storage, size)                       \
16   (struct vn_cs_encoder)                                                    \
17   {                                                                         \
18      .buffers = &VN_CS_ENCODER_BUFFER_INITIALIZER(storage),                 \
19      .buffer_count = 1, .buffer_max = 1, .current_buffer_size = size,       \
20      .cur = storage, .end = (const void *)(storage) + (size),               \
21   }
22
23#define VN_CS_ENCODER_INITIALIZER(buf, size)                                 \
24   (struct vn_cs_encoder)                                                    \
25   {                                                                         \
26      .buffers = (buf), .buffer_count = 1, .buffer_max = 1,                  \
27      .current_buffer_size = size, .cur = (buf)->base,                       \
28      .end = (buf)->base + (size),                                           \
29   }
30
31#define VN_CS_DECODER_INITIALIZER(storage, size)                             \
32   (struct vn_cs_decoder)                                                    \
33   {                                                                         \
34      .cur = storage, .end = (const void *)(storage) + (size),               \
35   }
36
37struct vn_cs_encoder_buffer {
38   struct vn_renderer_shmem *shmem;
39   size_t offset;
40   void *base;
41   size_t committed_size;
42};
43
44struct vn_cs_encoder {
45   struct vn_instance *instance; /* TODO shmem cache */
46   size_t min_buffer_size;
47   bool indirect;
48
49   bool fatal_error;
50
51   struct vn_cs_encoder_buffer *buffers;
52   uint32_t buffer_count;
53   uint32_t buffer_max;
54   size_t total_committed_size;
55
56   /* the current buffer is buffers[buffer_count - 1].shmem */
57   size_t current_buffer_size;
58   uint32_t current_buffer_roundtrip;
59
60   /* cur is the write pointer.  When cur passes end, the slow path is
61    * triggered.
62    */
63   void *cur;
64   const void *end;
65};
66
67struct vn_cs_decoder {
68   const void *cur;
69   const void *end;
70};
71
72void
73vn_cs_encoder_init_indirect(struct vn_cs_encoder *enc,
74                            struct vn_instance *instance,
75                            size_t min_size);
76
77void
78vn_cs_encoder_fini(struct vn_cs_encoder *enc);
79
80void
81vn_cs_encoder_reset(struct vn_cs_encoder *enc);
82
83static inline void
84vn_cs_encoder_set_fatal(const struct vn_cs_encoder *enc)
85{
86   /* This is fatal and should be treated as VK_ERROR_DEVICE_LOST or even
87    * abort().  Note that vn_cs_encoder_reset does not clear this.
88    */
89   ((struct vn_cs_encoder *)enc)->fatal_error = true;
90}
91
92static inline bool
93vn_cs_encoder_get_fatal(const struct vn_cs_encoder *enc)
94{
95   return enc->fatal_error;
96}
97
98static inline bool
99vn_cs_encoder_is_empty(const struct vn_cs_encoder *enc)
100{
101   return !enc->buffer_count || enc->cur == enc->buffers[0].base;
102}
103
104static inline size_t
105vn_cs_encoder_get_len(const struct vn_cs_encoder *enc)
106{
107   if (unlikely(!enc->buffer_count))
108      return 0;
109
110   size_t len = enc->total_committed_size;
111   const struct vn_cs_encoder_buffer *cur_buf =
112      &enc->buffers[enc->buffer_count - 1];
113   if (!cur_buf->committed_size)
114      len += enc->cur - cur_buf->base;
115   return len;
116}
117
118bool
119vn_cs_encoder_reserve_internal(struct vn_cs_encoder *enc, size_t size);
120
121/**
122 * Reserve space for commands.
123 */
124static inline bool
125vn_cs_encoder_reserve(struct vn_cs_encoder *enc, size_t size)
126{
127   if (unlikely(size > enc->end - enc->cur)) {
128      if (!vn_cs_encoder_reserve_internal(enc, size)) {
129         vn_cs_encoder_set_fatal(enc);
130         return false;
131      }
132      assert(size <= enc->end - enc->cur);
133   }
134
135   return true;
136}
137
138static inline void
139vn_cs_encoder_write(struct vn_cs_encoder *enc,
140                    size_t size,
141                    const void *val,
142                    size_t val_size)
143{
144   assert(val_size <= size);
145   assert(size <= enc->end - enc->cur);
146
147   /* we should not rely on the compiler to optimize away memcpy... */
148   memcpy(enc->cur, val, val_size);
149   enc->cur += size;
150}
151
152void
153vn_cs_encoder_commit(struct vn_cs_encoder *enc);
154
155static inline void
156vn_cs_decoder_init(struct vn_cs_decoder *dec, const void *data, size_t size)
157{
158   *dec = VN_CS_DECODER_INITIALIZER(data, size);
159}
160
161static inline void
162vn_cs_decoder_set_fatal(const struct vn_cs_decoder *dec)
163{
164   abort();
165}
166
167static inline bool
168vn_cs_decoder_peek_internal(const struct vn_cs_decoder *dec,
169                            size_t size,
170                            void *val,
171                            size_t val_size)
172{
173   assert(val_size <= size);
174
175   if (unlikely(size > dec->end - dec->cur)) {
176      vn_cs_decoder_set_fatal(dec);
177      memset(val, 0, val_size);
178      return false;
179   }
180
181   /* we should not rely on the compiler to optimize away memcpy... */
182   memcpy(val, dec->cur, val_size);
183   return true;
184}
185
186static inline void
187vn_cs_decoder_read(struct vn_cs_decoder *dec,
188                   size_t size,
189                   void *val,
190                   size_t val_size)
191{
192   if (vn_cs_decoder_peek_internal(dec, size, val, val_size))
193      dec->cur += size;
194}
195
196static inline void
197vn_cs_decoder_peek(const struct vn_cs_decoder *dec,
198                   size_t size,
199                   void *val,
200                   size_t val_size)
201{
202   vn_cs_decoder_peek_internal(dec, size, val, val_size);
203}
204
205static inline vn_object_id
206vn_cs_handle_load_id(const void **handle, VkObjectType type)
207{
208   return *handle ? vn_object_get_id(*handle, type) : 0;
209}
210
211static inline void
212vn_cs_handle_store_id(void **handle, vn_object_id id, VkObjectType type)
213{
214   vn_object_set_id(*handle, id, type);
215}
216
217#endif /* VN_CS_H */
218