1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2012 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "main/glthread_marshal.h"
25bf215546Sopenharmony_ci#include "main/dispatch.h"
26bf215546Sopenharmony_ci#include "main/bufferobj.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * Create an upload buffer. This is called from the app thread, so everything
30bf215546Sopenharmony_ci * has to be thread-safe in the driver.
31bf215546Sopenharmony_ci */
32bf215546Sopenharmony_cistatic struct gl_buffer_object *
33bf215546Sopenharmony_cinew_upload_buffer(struct gl_context *ctx, GLsizeiptr size, uint8_t **ptr)
34bf215546Sopenharmony_ci{
35bf215546Sopenharmony_ci   assert(ctx->GLThread.SupportsBufferUploads);
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_ci   struct gl_buffer_object *obj =
38bf215546Sopenharmony_ci      _mesa_bufferobj_alloc(ctx, -1);
39bf215546Sopenharmony_ci   if (!obj)
40bf215546Sopenharmony_ci      return NULL;
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci   obj->Immutable = true;
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci   if (!_mesa_bufferobj_data(ctx, GL_ARRAY_BUFFER, size, NULL,
45bf215546Sopenharmony_ci                          GL_WRITE_ONLY,
46bf215546Sopenharmony_ci                          GL_CLIENT_STORAGE_BIT | GL_MAP_WRITE_BIT,
47bf215546Sopenharmony_ci                          obj)) {
48bf215546Sopenharmony_ci      _mesa_delete_buffer_object(ctx, obj);
49bf215546Sopenharmony_ci      return NULL;
50bf215546Sopenharmony_ci   }
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   *ptr = _mesa_bufferobj_map_range(ctx, 0, size,
53bf215546Sopenharmony_ci                                 GL_MAP_WRITE_BIT |
54bf215546Sopenharmony_ci                                 GL_MAP_UNSYNCHRONIZED_BIT |
55bf215546Sopenharmony_ci                                 MESA_MAP_THREAD_SAFE_BIT,
56bf215546Sopenharmony_ci                                 obj, MAP_GLTHREAD);
57bf215546Sopenharmony_ci   if (!*ptr) {
58bf215546Sopenharmony_ci      _mesa_delete_buffer_object(ctx, obj);
59bf215546Sopenharmony_ci      return NULL;
60bf215546Sopenharmony_ci   }
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   return obj;
63bf215546Sopenharmony_ci}
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_civoid
66bf215546Sopenharmony_ci_mesa_glthread_upload(struct gl_context *ctx, const void *data,
67bf215546Sopenharmony_ci                      GLsizeiptr size, unsigned *out_offset,
68bf215546Sopenharmony_ci                      struct gl_buffer_object **out_buffer,
69bf215546Sopenharmony_ci                      uint8_t **out_ptr)
70bf215546Sopenharmony_ci{
71bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
72bf215546Sopenharmony_ci   const unsigned default_size = 1024 * 1024;
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   if (unlikely(size > INT_MAX))
75bf215546Sopenharmony_ci      return;
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   /* The alignment was chosen arbitrarily. */
78bf215546Sopenharmony_ci   unsigned offset = align(glthread->upload_offset, 8);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   /* Allocate a new buffer if needed. */
81bf215546Sopenharmony_ci   if (unlikely(!glthread->upload_buffer || offset + size > default_size)) {
82bf215546Sopenharmony_ci      /* If the size is greater than the buffer size, allocate a separate buffer
83bf215546Sopenharmony_ci       * just for this upload.
84bf215546Sopenharmony_ci       */
85bf215546Sopenharmony_ci      if (unlikely(size > default_size)) {
86bf215546Sopenharmony_ci         uint8_t *ptr;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci         assert(*out_buffer == NULL);
89bf215546Sopenharmony_ci         *out_buffer = new_upload_buffer(ctx, size, &ptr);
90bf215546Sopenharmony_ci         if (!*out_buffer)
91bf215546Sopenharmony_ci            return;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci         *out_offset = 0;
94bf215546Sopenharmony_ci         if (data)
95bf215546Sopenharmony_ci            memcpy(ptr, data, size);
96bf215546Sopenharmony_ci         else
97bf215546Sopenharmony_ci            *out_ptr = ptr;
98bf215546Sopenharmony_ci         return;
99bf215546Sopenharmony_ci      }
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci      if (glthread->upload_buffer_private_refcount > 0) {
102bf215546Sopenharmony_ci         p_atomic_add(&glthread->upload_buffer->RefCount,
103bf215546Sopenharmony_ci                      -glthread->upload_buffer_private_refcount);
104bf215546Sopenharmony_ci         glthread->upload_buffer_private_refcount = 0;
105bf215546Sopenharmony_ci      }
106bf215546Sopenharmony_ci      _mesa_reference_buffer_object(ctx, &glthread->upload_buffer, NULL);
107bf215546Sopenharmony_ci      glthread->upload_buffer =
108bf215546Sopenharmony_ci         new_upload_buffer(ctx, default_size, &glthread->upload_ptr);
109bf215546Sopenharmony_ci      glthread->upload_offset = 0;
110bf215546Sopenharmony_ci      offset = 0;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci      /* Since atomic operations are very very slow when 2 threads are not
113bf215546Sopenharmony_ci       * sharing one L3 cache (which can happen on AMD Zen), prevent using
114bf215546Sopenharmony_ci       * atomics as follows:
115bf215546Sopenharmony_ci       *
116bf215546Sopenharmony_ci       * This function has to return a buffer reference to the caller.
117bf215546Sopenharmony_ci       * Instead of atomic_inc for every call, it does all possible future
118bf215546Sopenharmony_ci       * increments in advance when the upload buffer is allocated.
119bf215546Sopenharmony_ci       * The maximum number of times the function can be called per upload
120bf215546Sopenharmony_ci       * buffer is default_size, because the minimum allocation size is 1.
121bf215546Sopenharmony_ci       * Therefore the function can only return default_size number of
122bf215546Sopenharmony_ci       * references at most, so we will never need more. This is the number
123bf215546Sopenharmony_ci       * that is added to RefCount at allocation.
124bf215546Sopenharmony_ci       *
125bf215546Sopenharmony_ci       * upload_buffer_private_refcount tracks how many buffer references
126bf215546Sopenharmony_ci       * are left to return to callers. If the buffer is full and there are
127bf215546Sopenharmony_ci       * still references left, they are atomically subtracted from RefCount
128bf215546Sopenharmony_ci       * before the buffer is unreferenced.
129bf215546Sopenharmony_ci       *
130bf215546Sopenharmony_ci       * This can increase performance by 20%.
131bf215546Sopenharmony_ci       */
132bf215546Sopenharmony_ci      glthread->upload_buffer->RefCount += default_size;
133bf215546Sopenharmony_ci      glthread->upload_buffer_private_refcount = default_size;
134bf215546Sopenharmony_ci   }
135bf215546Sopenharmony_ci
136bf215546Sopenharmony_ci   /* Upload data. */
137bf215546Sopenharmony_ci   if (data)
138bf215546Sopenharmony_ci      memcpy(glthread->upload_ptr + offset, data, size);
139bf215546Sopenharmony_ci   else
140bf215546Sopenharmony_ci      *out_ptr = glthread->upload_ptr + offset;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   glthread->upload_offset = offset + size;
143bf215546Sopenharmony_ci   *out_offset = offset;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   assert(*out_buffer == NULL);
146bf215546Sopenharmony_ci   assert(glthread->upload_buffer_private_refcount > 0);
147bf215546Sopenharmony_ci   *out_buffer = glthread->upload_buffer;
148bf215546Sopenharmony_ci   glthread->upload_buffer_private_refcount--;
149bf215546Sopenharmony_ci}
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_ci/** Tracks the current bindings for the vertex array and index array buffers.
152bf215546Sopenharmony_ci *
153bf215546Sopenharmony_ci * This is part of what we need to enable glthread on compat-GL contexts that
154bf215546Sopenharmony_ci * happen to use VBOs, without also supporting the full tracking of VBO vs
155bf215546Sopenharmony_ci * user vertex array bindings per attribute on each vertex array for
156bf215546Sopenharmony_ci * determining what to upload at draw call time.
157bf215546Sopenharmony_ci *
158bf215546Sopenharmony_ci * Note that GL core makes it so that a buffer binding with an invalid handle
159bf215546Sopenharmony_ci * in the "buffer" parameter will throw an error, and then a
160bf215546Sopenharmony_ci * glVertexAttribPointer() that followsmight not end up pointing at a VBO.
161bf215546Sopenharmony_ci * However, in GL core the draw call would throw an error as well, so we don't
162bf215546Sopenharmony_ci * really care if our tracking is wrong for this case -- we never need to
163bf215546Sopenharmony_ci * marshal user data for draw calls, and the unmarshal will just generate an
164bf215546Sopenharmony_ci * error or not as appropriate.
165bf215546Sopenharmony_ci *
166bf215546Sopenharmony_ci * For compatibility GL, we do need to accurately know whether the draw call
167bf215546Sopenharmony_ci * on the unmarshal side will dereference a user pointer or load data from a
168bf215546Sopenharmony_ci * VBO per vertex.  That would make it seem like we need to track whether a
169bf215546Sopenharmony_ci * "buffer" is valid, so that we can know when an error will be generated
170bf215546Sopenharmony_ci * instead of updating the binding.  However, compat GL has the ridiculous
171bf215546Sopenharmony_ci * feature that if you pass a bad name, it just gens a buffer object for you,
172bf215546Sopenharmony_ci * so we escape without having to know if things are valid or not.
173bf215546Sopenharmony_ci */
174bf215546Sopenharmony_civoid
175bf215546Sopenharmony_ci_mesa_glthread_BindBuffer(struct gl_context *ctx, GLenum target, GLuint buffer)
176bf215546Sopenharmony_ci{
177bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
178bf215546Sopenharmony_ci
179bf215546Sopenharmony_ci   switch (target) {
180bf215546Sopenharmony_ci   case GL_ARRAY_BUFFER:
181bf215546Sopenharmony_ci      glthread->CurrentArrayBufferName = buffer;
182bf215546Sopenharmony_ci      break;
183bf215546Sopenharmony_ci   case GL_ELEMENT_ARRAY_BUFFER:
184bf215546Sopenharmony_ci      /* The current element array buffer binding is actually tracked in the
185bf215546Sopenharmony_ci       * vertex array object instead of the context, so this would need to
186bf215546Sopenharmony_ci       * change on vertex array object updates.
187bf215546Sopenharmony_ci       */
188bf215546Sopenharmony_ci      glthread->CurrentVAO->CurrentElementBufferName = buffer;
189bf215546Sopenharmony_ci      break;
190bf215546Sopenharmony_ci   case GL_DRAW_INDIRECT_BUFFER:
191bf215546Sopenharmony_ci      glthread->CurrentDrawIndirectBufferName = buffer;
192bf215546Sopenharmony_ci      break;
193bf215546Sopenharmony_ci   case GL_PIXEL_PACK_BUFFER:
194bf215546Sopenharmony_ci      glthread->CurrentPixelPackBufferName = buffer;
195bf215546Sopenharmony_ci      break;
196bf215546Sopenharmony_ci   case GL_PIXEL_UNPACK_BUFFER:
197bf215546Sopenharmony_ci      glthread->CurrentPixelUnpackBufferName = buffer;
198bf215546Sopenharmony_ci      break;
199bf215546Sopenharmony_ci   case GL_QUERY_BUFFER:
200bf215546Sopenharmony_ci      glthread->CurrentQueryBufferName = buffer;
201bf215546Sopenharmony_ci      break;
202bf215546Sopenharmony_ci   }
203bf215546Sopenharmony_ci}
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_civoid
206bf215546Sopenharmony_ci_mesa_glthread_DeleteBuffers(struct gl_context *ctx, GLsizei n,
207bf215546Sopenharmony_ci                             const GLuint *buffers)
208bf215546Sopenharmony_ci{
209bf215546Sopenharmony_ci   struct glthread_state *glthread = &ctx->GLThread;
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   if (!buffers || n < 0)
212bf215546Sopenharmony_ci      return;
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   for (unsigned i = 0; i < n; i++) {
215bf215546Sopenharmony_ci      GLuint id = buffers[i];
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci      if (id == glthread->CurrentArrayBufferName)
218bf215546Sopenharmony_ci         _mesa_glthread_BindBuffer(ctx, GL_ARRAY_BUFFER, 0);
219bf215546Sopenharmony_ci      if (id == glthread->CurrentVAO->CurrentElementBufferName)
220bf215546Sopenharmony_ci         _mesa_glthread_BindBuffer(ctx, GL_ELEMENT_ARRAY_BUFFER, 0);
221bf215546Sopenharmony_ci      if (id == glthread->CurrentDrawIndirectBufferName)
222bf215546Sopenharmony_ci         _mesa_glthread_BindBuffer(ctx, GL_DRAW_INDIRECT_BUFFER, 0);
223bf215546Sopenharmony_ci      if (id == glthread->CurrentPixelPackBufferName)
224bf215546Sopenharmony_ci         _mesa_glthread_BindBuffer(ctx, GL_PIXEL_PACK_BUFFER, 0);
225bf215546Sopenharmony_ci      if (id == glthread->CurrentPixelUnpackBufferName)
226bf215546Sopenharmony_ci         _mesa_glthread_BindBuffer(ctx, GL_PIXEL_UNPACK_BUFFER, 0);
227bf215546Sopenharmony_ci   }
228bf215546Sopenharmony_ci}
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci/* BufferData: marshalled asynchronously */
231bf215546Sopenharmony_cistruct marshal_cmd_BufferData
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   struct marshal_cmd_base cmd_base;
234bf215546Sopenharmony_ci   GLuint target_or_name;
235bf215546Sopenharmony_ci   GLsizeiptr size;
236bf215546Sopenharmony_ci   GLenum usage;
237bf215546Sopenharmony_ci   const GLvoid *data_external_mem;
238bf215546Sopenharmony_ci   bool data_null; /* If set, no data follows for "data" */
239bf215546Sopenharmony_ci   bool named;
240bf215546Sopenharmony_ci   bool ext_dsa;
241bf215546Sopenharmony_ci   /* Next size bytes are GLubyte data[size] */
242bf215546Sopenharmony_ci};
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ciuint32_t
245bf215546Sopenharmony_ci_mesa_unmarshal_BufferData(struct gl_context *ctx,
246bf215546Sopenharmony_ci                           const struct marshal_cmd_BufferData *cmd,
247bf215546Sopenharmony_ci                           const uint64_t *last)
248bf215546Sopenharmony_ci{
249bf215546Sopenharmony_ci   const GLuint target_or_name = cmd->target_or_name;
250bf215546Sopenharmony_ci   const GLsizei size = cmd->size;
251bf215546Sopenharmony_ci   const GLenum usage = cmd->usage;
252bf215546Sopenharmony_ci   const void *data;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   if (cmd->data_null)
255bf215546Sopenharmony_ci      data = NULL;
256bf215546Sopenharmony_ci   else if (!cmd->named && target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD)
257bf215546Sopenharmony_ci      data = cmd->data_external_mem;
258bf215546Sopenharmony_ci   else
259bf215546Sopenharmony_ci      data = (const void *) (cmd + 1);
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   if (cmd->ext_dsa) {
262bf215546Sopenharmony_ci      CALL_NamedBufferDataEXT(ctx->CurrentServerDispatch,
263bf215546Sopenharmony_ci                              (target_or_name, size, data, usage));
264bf215546Sopenharmony_ci   } else if (cmd->named) {
265bf215546Sopenharmony_ci      CALL_NamedBufferData(ctx->CurrentServerDispatch,
266bf215546Sopenharmony_ci                           (target_or_name, size, data, usage));
267bf215546Sopenharmony_ci   } else {
268bf215546Sopenharmony_ci      CALL_BufferData(ctx->CurrentServerDispatch,
269bf215546Sopenharmony_ci                      (target_or_name, size, data, usage));
270bf215546Sopenharmony_ci   }
271bf215546Sopenharmony_ci   return cmd->cmd_base.cmd_size;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ciuint32_t
275bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferData(struct gl_context *ctx,
276bf215546Sopenharmony_ci                                const struct marshal_cmd_NamedBufferData *cmd,
277bf215546Sopenharmony_ci                                const uint64_t *last)
278bf215546Sopenharmony_ci{
279bf215546Sopenharmony_ci   unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
280bf215546Sopenharmony_ci   return 0;
281bf215546Sopenharmony_ci}
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ciuint32_t
284bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferDataEXT(struct gl_context *ctx,
285bf215546Sopenharmony_ci                                   const struct marshal_cmd_NamedBufferDataEXT *cmd,
286bf215546Sopenharmony_ci                                   const uint64_t *last)
287bf215546Sopenharmony_ci{
288bf215546Sopenharmony_ci   unreachable("never used - all BufferData variants use DISPATCH_CMD_BufferData");
289bf215546Sopenharmony_ci   return 0;
290bf215546Sopenharmony_ci}
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_cistatic void
293bf215546Sopenharmony_ci_mesa_marshal_BufferData_merged(GLuint target_or_name, GLsizeiptr size,
294bf215546Sopenharmony_ci                                const GLvoid *data, GLenum usage, bool named,
295bf215546Sopenharmony_ci                                bool ext_dsa, const char *func)
296bf215546Sopenharmony_ci{
297bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
298bf215546Sopenharmony_ci   bool external_mem = !named &&
299bf215546Sopenharmony_ci                       target_or_name == GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD;
300bf215546Sopenharmony_ci   bool copy_data = data && !external_mem;
301bf215546Sopenharmony_ci   size_t cmd_size = sizeof(struct marshal_cmd_BufferData) + (copy_data ? size : 0);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   if (unlikely(size < 0 || size > INT_MAX || cmd_size > MARSHAL_MAX_CMD_SIZE ||
304bf215546Sopenharmony_ci                (named && target_or_name == 0))) {
305bf215546Sopenharmony_ci      _mesa_glthread_finish_before(ctx, func);
306bf215546Sopenharmony_ci      if (named) {
307bf215546Sopenharmony_ci         CALL_NamedBufferData(ctx->CurrentServerDispatch,
308bf215546Sopenharmony_ci                              (target_or_name, size, data, usage));
309bf215546Sopenharmony_ci      } else {
310bf215546Sopenharmony_ci         CALL_BufferData(ctx->CurrentServerDispatch,
311bf215546Sopenharmony_ci                         (target_or_name, size, data, usage));
312bf215546Sopenharmony_ci      }
313bf215546Sopenharmony_ci      return;
314bf215546Sopenharmony_ci   }
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci   struct marshal_cmd_BufferData *cmd =
317bf215546Sopenharmony_ci      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferData,
318bf215546Sopenharmony_ci                                      cmd_size);
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci   cmd->target_or_name = target_or_name;
321bf215546Sopenharmony_ci   cmd->size = size;
322bf215546Sopenharmony_ci   cmd->usage = usage;
323bf215546Sopenharmony_ci   cmd->data_null = !data;
324bf215546Sopenharmony_ci   cmd->named = named;
325bf215546Sopenharmony_ci   cmd->ext_dsa = ext_dsa;
326bf215546Sopenharmony_ci   cmd->data_external_mem = data;
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   if (copy_data) {
329bf215546Sopenharmony_ci      char *variable_data = (char *) (cmd + 1);
330bf215546Sopenharmony_ci      memcpy(variable_data, data, size);
331bf215546Sopenharmony_ci   }
332bf215546Sopenharmony_ci}
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_civoid GLAPIENTRY
335bf215546Sopenharmony_ci_mesa_marshal_BufferData(GLenum target, GLsizeiptr size, const GLvoid * data,
336bf215546Sopenharmony_ci                         GLenum usage)
337bf215546Sopenharmony_ci{
338bf215546Sopenharmony_ci   _mesa_marshal_BufferData_merged(target, size, data, usage, false, false,
339bf215546Sopenharmony_ci                                   "BufferData");
340bf215546Sopenharmony_ci}
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_civoid GLAPIENTRY
343bf215546Sopenharmony_ci_mesa_marshal_NamedBufferData(GLuint buffer, GLsizeiptr size,
344bf215546Sopenharmony_ci                              const GLvoid * data, GLenum usage)
345bf215546Sopenharmony_ci{
346bf215546Sopenharmony_ci   _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, false,
347bf215546Sopenharmony_ci                                   "NamedBufferData");
348bf215546Sopenharmony_ci}
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_civoid GLAPIENTRY
351bf215546Sopenharmony_ci_mesa_marshal_NamedBufferDataEXT(GLuint buffer, GLsizeiptr size,
352bf215546Sopenharmony_ci                                 const GLvoid *data, GLenum usage)
353bf215546Sopenharmony_ci{
354bf215546Sopenharmony_ci   _mesa_marshal_BufferData_merged(buffer, size, data, usage, true, true,
355bf215546Sopenharmony_ci                                   "NamedBufferDataEXT");
356bf215546Sopenharmony_ci}
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci/* BufferSubData: marshalled asynchronously */
360bf215546Sopenharmony_cistruct marshal_cmd_BufferSubData
361bf215546Sopenharmony_ci{
362bf215546Sopenharmony_ci   struct marshal_cmd_base cmd_base;
363bf215546Sopenharmony_ci   GLenum target_or_name;
364bf215546Sopenharmony_ci   GLintptr offset;
365bf215546Sopenharmony_ci   GLsizeiptr size;
366bf215546Sopenharmony_ci   bool named;
367bf215546Sopenharmony_ci   bool ext_dsa;
368bf215546Sopenharmony_ci   /* Next size bytes are GLubyte data[size] */
369bf215546Sopenharmony_ci};
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ciuint32_t
372bf215546Sopenharmony_ci_mesa_unmarshal_BufferSubData(struct gl_context *ctx,
373bf215546Sopenharmony_ci                              const struct marshal_cmd_BufferSubData *cmd,
374bf215546Sopenharmony_ci                              const uint64_t *last)
375bf215546Sopenharmony_ci{
376bf215546Sopenharmony_ci   const GLenum target_or_name = cmd->target_or_name;
377bf215546Sopenharmony_ci   const GLintptr offset = cmd->offset;
378bf215546Sopenharmony_ci   const GLsizeiptr size = cmd->size;
379bf215546Sopenharmony_ci   const void *data = (const void *) (cmd + 1);
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   if (cmd->ext_dsa) {
382bf215546Sopenharmony_ci      CALL_NamedBufferSubDataEXT(ctx->CurrentServerDispatch,
383bf215546Sopenharmony_ci                                 (target_or_name, offset, size, data));
384bf215546Sopenharmony_ci   } else if (cmd->named) {
385bf215546Sopenharmony_ci      CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
386bf215546Sopenharmony_ci                              (target_or_name, offset, size, data));
387bf215546Sopenharmony_ci   } else {
388bf215546Sopenharmony_ci      CALL_BufferSubData(ctx->CurrentServerDispatch,
389bf215546Sopenharmony_ci                         (target_or_name, offset, size, data));
390bf215546Sopenharmony_ci   }
391bf215546Sopenharmony_ci   return cmd->cmd_base.cmd_size;
392bf215546Sopenharmony_ci}
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ciuint32_t
395bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferSubData(struct gl_context *ctx,
396bf215546Sopenharmony_ci                                   const struct marshal_cmd_NamedBufferSubData *cmd,
397bf215546Sopenharmony_ci                                   const uint64_t *last)
398bf215546Sopenharmony_ci{
399bf215546Sopenharmony_ci   unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
400bf215546Sopenharmony_ci   return 0;
401bf215546Sopenharmony_ci}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ciuint32_t
404bf215546Sopenharmony_ci_mesa_unmarshal_NamedBufferSubDataEXT(struct gl_context *ctx,
405bf215546Sopenharmony_ci                                      const struct marshal_cmd_NamedBufferSubDataEXT *cmd,
406bf215546Sopenharmony_ci                                      const uint64_t *last)
407bf215546Sopenharmony_ci{
408bf215546Sopenharmony_ci   unreachable("never used - all BufferSubData variants use DISPATCH_CMD_BufferSubData");
409bf215546Sopenharmony_ci   return 0;
410bf215546Sopenharmony_ci}
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_cistatic void
413bf215546Sopenharmony_ci_mesa_marshal_BufferSubData_merged(GLuint target_or_name, GLintptr offset,
414bf215546Sopenharmony_ci                                   GLsizeiptr size, const GLvoid *data,
415bf215546Sopenharmony_ci                                   bool named, bool ext_dsa, const char *func)
416bf215546Sopenharmony_ci{
417bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
418bf215546Sopenharmony_ci   size_t cmd_size = sizeof(struct marshal_cmd_BufferSubData) + size;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   /* Fast path: Copy the data to an upload buffer, and use the GPU
421bf215546Sopenharmony_ci    * to copy the uploaded data to the destination buffer.
422bf215546Sopenharmony_ci    */
423bf215546Sopenharmony_ci   /* TODO: Handle offset == 0 && size < buffer_size.
424bf215546Sopenharmony_ci    *       If offset == 0 and size == buffer_size, it's better to discard
425bf215546Sopenharmony_ci    *       the buffer storage, but we don't know the buffer size in glthread.
426bf215546Sopenharmony_ci    */
427bf215546Sopenharmony_ci   if (ctx->GLThread.SupportsBufferUploads &&
428bf215546Sopenharmony_ci       data && offset > 0 && size > 0) {
429bf215546Sopenharmony_ci      struct gl_buffer_object *upload_buffer = NULL;
430bf215546Sopenharmony_ci      unsigned upload_offset = 0;
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci      _mesa_glthread_upload(ctx, data, size, &upload_offset, &upload_buffer,
433bf215546Sopenharmony_ci                            NULL);
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci      if (upload_buffer) {
436bf215546Sopenharmony_ci         _mesa_marshal_InternalBufferSubDataCopyMESA((GLintptr)upload_buffer,
437bf215546Sopenharmony_ci                                                     upload_offset,
438bf215546Sopenharmony_ci                                                     target_or_name,
439bf215546Sopenharmony_ci                                                     offset, size, named,
440bf215546Sopenharmony_ci                                                     ext_dsa);
441bf215546Sopenharmony_ci         return;
442bf215546Sopenharmony_ci      }
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   if (unlikely(size < 0 || size > INT_MAX || cmd_size < 0 ||
446bf215546Sopenharmony_ci                cmd_size > MARSHAL_MAX_CMD_SIZE || !data ||
447bf215546Sopenharmony_ci                (named && target_or_name == 0))) {
448bf215546Sopenharmony_ci      _mesa_glthread_finish_before(ctx, func);
449bf215546Sopenharmony_ci      if (named) {
450bf215546Sopenharmony_ci         CALL_NamedBufferSubData(ctx->CurrentServerDispatch,
451bf215546Sopenharmony_ci                                 (target_or_name, offset, size, data));
452bf215546Sopenharmony_ci      } else {
453bf215546Sopenharmony_ci         CALL_BufferSubData(ctx->CurrentServerDispatch,
454bf215546Sopenharmony_ci                            (target_or_name, offset, size, data));
455bf215546Sopenharmony_ci      }
456bf215546Sopenharmony_ci      return;
457bf215546Sopenharmony_ci   }
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   struct marshal_cmd_BufferSubData *cmd =
460bf215546Sopenharmony_ci      _mesa_glthread_allocate_command(ctx, DISPATCH_CMD_BufferSubData,
461bf215546Sopenharmony_ci                                      cmd_size);
462bf215546Sopenharmony_ci   cmd->target_or_name = target_or_name;
463bf215546Sopenharmony_ci   cmd->offset = offset;
464bf215546Sopenharmony_ci   cmd->size = size;
465bf215546Sopenharmony_ci   cmd->named = named;
466bf215546Sopenharmony_ci   cmd->ext_dsa = ext_dsa;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   char *variable_data = (char *) (cmd + 1);
469bf215546Sopenharmony_ci   memcpy(variable_data, data, size);
470bf215546Sopenharmony_ci}
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_civoid GLAPIENTRY
473bf215546Sopenharmony_ci_mesa_marshal_BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,
474bf215546Sopenharmony_ci                            const GLvoid * data)
475bf215546Sopenharmony_ci{
476bf215546Sopenharmony_ci   _mesa_marshal_BufferSubData_merged(target, offset, size, data, false,
477bf215546Sopenharmony_ci                                      false, "BufferSubData");
478bf215546Sopenharmony_ci}
479bf215546Sopenharmony_ci
480bf215546Sopenharmony_civoid GLAPIENTRY
481bf215546Sopenharmony_ci_mesa_marshal_NamedBufferSubData(GLuint buffer, GLintptr offset,
482bf215546Sopenharmony_ci                                 GLsizeiptr size, const GLvoid * data)
483bf215546Sopenharmony_ci{
484bf215546Sopenharmony_ci   _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
485bf215546Sopenharmony_ci                                      false, "NamedBufferSubData");
486bf215546Sopenharmony_ci}
487bf215546Sopenharmony_ci
488bf215546Sopenharmony_civoid GLAPIENTRY
489bf215546Sopenharmony_ci_mesa_marshal_NamedBufferSubDataEXT(GLuint buffer, GLintptr offset,
490bf215546Sopenharmony_ci                                    GLsizeiptr size, const GLvoid * data)
491bf215546Sopenharmony_ci{
492bf215546Sopenharmony_ci   _mesa_marshal_BufferSubData_merged(buffer, offset, size, data, true,
493bf215546Sopenharmony_ci                                      true, "NamedBufferSubDataEXT");
494bf215546Sopenharmony_ci}
495