xref: /third_party/mesa3d/src/mesa/main/feedback.c (revision bf215546)
1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
8bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
9bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
10bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
12bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
15bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci/**
27bf215546Sopenharmony_ci * \file feedback.c
28bf215546Sopenharmony_ci * Selection and feedback modes functions.
29bf215546Sopenharmony_ci */
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "glheader.h"
33bf215546Sopenharmony_ci#include "c99_alloca.h"
34bf215546Sopenharmony_ci#include "context.h"
35bf215546Sopenharmony_ci#include "enums.h"
36bf215546Sopenharmony_ci#include "feedback.h"
37bf215546Sopenharmony_ci#include "macros.h"
38bf215546Sopenharmony_ci#include "mtypes.h"
39bf215546Sopenharmony_ci#include "api_exec_decl.h"
40bf215546Sopenharmony_ci#include "bufferobj.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#include "state_tracker/st_cb_feedback.h"
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci#define FB_3D		0x01
45bf215546Sopenharmony_ci#define FB_4D		0x02
46bf215546Sopenharmony_ci#define FB_COLOR	0x04
47bf215546Sopenharmony_ci#define FB_TEXTURE	0X08
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_civoid GLAPIENTRY
52bf215546Sopenharmony_ci_mesa_FeedbackBuffer( GLsizei size, GLenum type, GLfloat *buffer )
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   if (ctx->RenderMode==GL_FEEDBACK) {
57bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_OPERATION, "glFeedbackBuffer" );
58bf215546Sopenharmony_ci      return;
59bf215546Sopenharmony_ci   }
60bf215546Sopenharmony_ci   if (size<0) {
61bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(size<0)" );
62bf215546Sopenharmony_ci      return;
63bf215546Sopenharmony_ci   }
64bf215546Sopenharmony_ci   if (!buffer && size > 0) {
65bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_VALUE, "glFeedbackBuffer(buffer==NULL)" );
66bf215546Sopenharmony_ci      ctx->Feedback.BufferSize = 0;
67bf215546Sopenharmony_ci      return;
68bf215546Sopenharmony_ci   }
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   switch (type) {
71bf215546Sopenharmony_ci      case GL_2D:
72bf215546Sopenharmony_ci	 ctx->Feedback._Mask = 0;
73bf215546Sopenharmony_ci	 break;
74bf215546Sopenharmony_ci      case GL_3D:
75bf215546Sopenharmony_ci	 ctx->Feedback._Mask = FB_3D;
76bf215546Sopenharmony_ci	 break;
77bf215546Sopenharmony_ci      case GL_3D_COLOR:
78bf215546Sopenharmony_ci	 ctx->Feedback._Mask = (FB_3D | FB_COLOR);
79bf215546Sopenharmony_ci	 break;
80bf215546Sopenharmony_ci      case GL_3D_COLOR_TEXTURE:
81bf215546Sopenharmony_ci	 ctx->Feedback._Mask = (FB_3D | FB_COLOR | FB_TEXTURE);
82bf215546Sopenharmony_ci	 break;
83bf215546Sopenharmony_ci      case GL_4D_COLOR_TEXTURE:
84bf215546Sopenharmony_ci	 ctx->Feedback._Mask = (FB_3D | FB_4D | FB_COLOR | FB_TEXTURE);
85bf215546Sopenharmony_ci	 break;
86bf215546Sopenharmony_ci      default:
87bf215546Sopenharmony_ci         _mesa_error( ctx, GL_INVALID_ENUM, "glFeedbackBuffer" );
88bf215546Sopenharmony_ci	 return;
89bf215546Sopenharmony_ci   }
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, _NEW_RENDERMODE, 0); /* Always flush */
92bf215546Sopenharmony_ci   ctx->Feedback.Type = type;
93bf215546Sopenharmony_ci   ctx->Feedback.BufferSize = size;
94bf215546Sopenharmony_ci   ctx->Feedback.Buffer = buffer;
95bf215546Sopenharmony_ci   ctx->Feedback.Count = 0;	              /* Because of this. */
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_civoid GLAPIENTRY
100bf215546Sopenharmony_ci_mesa_PassThrough( GLfloat token )
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   if (ctx->RenderMode==GL_FEEDBACK) {
105bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, 0);
106bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, (GLfloat) (GLint) GL_PASS_THROUGH_TOKEN );
107bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, token );
108bf215546Sopenharmony_ci   }
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci/**
113bf215546Sopenharmony_ci * Put a vertex into the feedback buffer.
114bf215546Sopenharmony_ci */
115bf215546Sopenharmony_civoid
116bf215546Sopenharmony_ci_mesa_feedback_vertex(struct gl_context *ctx,
117bf215546Sopenharmony_ci                      const GLfloat win[4],
118bf215546Sopenharmony_ci                      const GLfloat color[4],
119bf215546Sopenharmony_ci                      const GLfloat texcoord[4])
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   _mesa_feedback_token( ctx, win[0] );
122bf215546Sopenharmony_ci   _mesa_feedback_token( ctx, win[1] );
123bf215546Sopenharmony_ci   if (ctx->Feedback._Mask & FB_3D) {
124bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, win[2] );
125bf215546Sopenharmony_ci   }
126bf215546Sopenharmony_ci   if (ctx->Feedback._Mask & FB_4D) {
127bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, win[3] );
128bf215546Sopenharmony_ci   }
129bf215546Sopenharmony_ci   if (ctx->Feedback._Mask & FB_COLOR) {
130bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, color[0] );
131bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, color[1] );
132bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, color[2] );
133bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, color[3] );
134bf215546Sopenharmony_ci   }
135bf215546Sopenharmony_ci   if (ctx->Feedback._Mask & FB_TEXTURE) {
136bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, texcoord[0] );
137bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, texcoord[1] );
138bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, texcoord[2] );
139bf215546Sopenharmony_ci      _mesa_feedback_token( ctx, texcoord[3] );
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci}
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci/**********************************************************************/
145bf215546Sopenharmony_ci/** \name Selection */
146bf215546Sopenharmony_ci/*@{*/
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci/**
149bf215546Sopenharmony_ci * Establish a buffer for selection mode values.
150bf215546Sopenharmony_ci *
151bf215546Sopenharmony_ci * \param size buffer size.
152bf215546Sopenharmony_ci * \param buffer buffer.
153bf215546Sopenharmony_ci *
154bf215546Sopenharmony_ci * \sa glSelectBuffer().
155bf215546Sopenharmony_ci *
156bf215546Sopenharmony_ci * \note this function can't be put in a display list.
157bf215546Sopenharmony_ci *
158bf215546Sopenharmony_ci * Verifies we're not in selection mode, flushes the vertices and initialize
159bf215546Sopenharmony_ci * the fields in __struct gl_contextRec::Select with the given buffer.
160bf215546Sopenharmony_ci */
161bf215546Sopenharmony_civoid GLAPIENTRY
162bf215546Sopenharmony_ci_mesa_SelectBuffer( GLsizei size, GLuint *buffer )
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   if (size < 0) {
167bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glSelectBuffer(size)");
168bf215546Sopenharmony_ci      return;
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   if (ctx->RenderMode==GL_SELECT) {
172bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_OPERATION, "glSelectBuffer" );
173bf215546Sopenharmony_ci      return;			/* KW: added return */
174bf215546Sopenharmony_ci   }
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, _NEW_RENDERMODE, 0);
177bf215546Sopenharmony_ci   ctx->Select.Buffer = buffer;
178bf215546Sopenharmony_ci   ctx->Select.BufferSize = size;
179bf215546Sopenharmony_ci   ctx->Select.BufferCount = 0;
180bf215546Sopenharmony_ci   ctx->Select.HitFlag = GL_FALSE;
181bf215546Sopenharmony_ci   ctx->Select.HitMinZ = 1.0;
182bf215546Sopenharmony_ci   ctx->Select.HitMaxZ = 0.0;
183bf215546Sopenharmony_ci}
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci/**
187bf215546Sopenharmony_ci * Write a value of a record into the selection buffer.
188bf215546Sopenharmony_ci *
189bf215546Sopenharmony_ci * \param ctx GL context.
190bf215546Sopenharmony_ci * \param value value.
191bf215546Sopenharmony_ci *
192bf215546Sopenharmony_ci * Verifies there is free space in the buffer to write the value and
193bf215546Sopenharmony_ci * increments the pointer.
194bf215546Sopenharmony_ci */
195bf215546Sopenharmony_cistatic inline void
196bf215546Sopenharmony_ciwrite_record(struct gl_context *ctx, GLuint value)
197bf215546Sopenharmony_ci{
198bf215546Sopenharmony_ci   if (ctx->Select.BufferCount < ctx->Select.BufferSize) {
199bf215546Sopenharmony_ci      ctx->Select.Buffer[ctx->Select.BufferCount] = value;
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci   ctx->Select.BufferCount++;
202bf215546Sopenharmony_ci}
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci
205bf215546Sopenharmony_ci/**
206bf215546Sopenharmony_ci * Update the hit flag and the maximum and minimum depth values.
207bf215546Sopenharmony_ci *
208bf215546Sopenharmony_ci * \param ctx GL context.
209bf215546Sopenharmony_ci * \param z depth.
210bf215546Sopenharmony_ci *
211bf215546Sopenharmony_ci * Sets gl_selection::HitFlag and updates gl_selection::HitMinZ and
212bf215546Sopenharmony_ci * gl_selection::HitMaxZ.
213bf215546Sopenharmony_ci */
214bf215546Sopenharmony_civoid
215bf215546Sopenharmony_ci_mesa_update_hitflag(struct gl_context *ctx, GLfloat z)
216bf215546Sopenharmony_ci{
217bf215546Sopenharmony_ci   ctx->Select.HitFlag = GL_TRUE;
218bf215546Sopenharmony_ci   if (z < ctx->Select.HitMinZ) {
219bf215546Sopenharmony_ci      ctx->Select.HitMinZ = z;
220bf215546Sopenharmony_ci   }
221bf215546Sopenharmony_ci   if (z > ctx->Select.HitMaxZ) {
222bf215546Sopenharmony_ci      ctx->Select.HitMaxZ = z;
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci}
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_cistatic void
227bf215546Sopenharmony_cialloc_select_resource(struct gl_context *ctx)
228bf215546Sopenharmony_ci{
229bf215546Sopenharmony_ci   struct gl_selection *s = &ctx->Select;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (!ctx->Const.HardwareAcceleratedSelect)
232bf215546Sopenharmony_ci      return;
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   if (!ctx->HWSelectModeBeginEnd) {
235bf215546Sopenharmony_ci      ctx->HWSelectModeBeginEnd = _mesa_alloc_dispatch_table(false);
236bf215546Sopenharmony_ci      if (!ctx->HWSelectModeBeginEnd) {
237bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "Cannot allocate HWSelectModeBeginEnd");
238bf215546Sopenharmony_ci         return;
239bf215546Sopenharmony_ci      }
240bf215546Sopenharmony_ci      vbo_install_hw_select_begin_end(ctx);
241bf215546Sopenharmony_ci   }
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   if (!s->SaveBuffer) {
244bf215546Sopenharmony_ci      s->SaveBuffer = malloc(NAME_STACK_BUFFER_SIZE);
245bf215546Sopenharmony_ci      if (!s->SaveBuffer) {
246bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "Cannot allocate name stack save buffer");
247bf215546Sopenharmony_ci         return;
248bf215546Sopenharmony_ci      }
249bf215546Sopenharmony_ci   }
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   if (!s->Result) {
252bf215546Sopenharmony_ci      s->Result = _mesa_bufferobj_alloc(ctx, -1);
253bf215546Sopenharmony_ci      if (!s->Result) {
254bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "Cannot allocate select result buffer");
255bf215546Sopenharmony_ci         return;
256bf215546Sopenharmony_ci      }
257bf215546Sopenharmony_ci
258bf215546Sopenharmony_ci      GLuint init_result[MAX_NAME_STACK_RESULT_NUM * 3];
259bf215546Sopenharmony_ci      for (int i = 0; i < MAX_NAME_STACK_RESULT_NUM; i++) {
260bf215546Sopenharmony_ci         init_result[i * 3] = 0;              /* hit */
261bf215546Sopenharmony_ci         init_result[i * 3 + 1] = 0xffffffff; /* minz */
262bf215546Sopenharmony_ci         init_result[i * 3 + 2] = 0;          /* maxz */
263bf215546Sopenharmony_ci      }
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci      bool success = _mesa_bufferobj_data(ctx,
266bf215546Sopenharmony_ci                                          GL_SHADER_STORAGE_BUFFER,
267bf215546Sopenharmony_ci                                          sizeof(init_result),
268bf215546Sopenharmony_ci                                          init_result,
269bf215546Sopenharmony_ci                                          GL_STATIC_DRAW, 0,
270bf215546Sopenharmony_ci                                          s->Result);
271bf215546Sopenharmony_ci      if (!success) {
272bf215546Sopenharmony_ci         _mesa_reference_buffer_object(ctx, &s->Result, NULL);
273bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "Cannot init result buffer");
274bf215546Sopenharmony_ci         return;
275bf215546Sopenharmony_ci      }
276bf215546Sopenharmony_ci   }
277bf215546Sopenharmony_ci}
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_cistatic bool
280bf215546Sopenharmony_cisave_used_name_stack(struct gl_context *ctx)
281bf215546Sopenharmony_ci{
282bf215546Sopenharmony_ci   struct gl_selection *s = &ctx->Select;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   if (!ctx->Const.HardwareAcceleratedSelect)
285bf215546Sopenharmony_ci      return false;
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   /* We have two kinds of name stack user:
288bf215546Sopenharmony_ci    *   1. glRasterPos (CPU based) will set HitFlag
289bf215546Sopenharmony_ci    *   2. draw call for GPU will set ResultUsed
290bf215546Sopenharmony_ci    */
291bf215546Sopenharmony_ci   if (!s->ResultUsed && !s->HitFlag)
292bf215546Sopenharmony_ci      return false;
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   void *save = (char *)s->SaveBuffer + s->SaveBufferTail;
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   /* save meta data */
297bf215546Sopenharmony_ci   uint8_t *metadata = save;
298bf215546Sopenharmony_ci   metadata[0] = s->HitFlag;
299bf215546Sopenharmony_ci   metadata[1] = s->ResultUsed;
300bf215546Sopenharmony_ci   metadata[2] = s->NameStackDepth;
301bf215546Sopenharmony_ci   metadata[3] = 0;
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   /* save hit data */
304bf215546Sopenharmony_ci   int index = 1;
305bf215546Sopenharmony_ci   if (s->HitFlag) {
306bf215546Sopenharmony_ci      float *hit = save;
307bf215546Sopenharmony_ci      hit[index++] = s->HitMinZ;
308bf215546Sopenharmony_ci      hit[index++] = s->HitMaxZ;
309bf215546Sopenharmony_ci   }
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   /* save name stack */
312bf215546Sopenharmony_ci   memcpy((uint32_t *)save + index, s->NameStack, s->NameStackDepth * sizeof(GLuint));
313bf215546Sopenharmony_ci   index += s->NameStackDepth;
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   s->SaveBufferTail += index * sizeof(GLuint);
316bf215546Sopenharmony_ci   s->SavedStackNum++;
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   /* if current slot has been used, store result to next slot in result buffer */
319bf215546Sopenharmony_ci   if (s->ResultUsed)
320bf215546Sopenharmony_ci      s->ResultOffset += 3 * sizeof(GLuint);
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   /* reset fields */
323bf215546Sopenharmony_ci   s->HitFlag = GL_FALSE;
324bf215546Sopenharmony_ci   s->HitMinZ = 1.0;
325bf215546Sopenharmony_ci   s->HitMaxZ = 0;
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   s->ResultUsed = GL_FALSE;
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci   /* return true if we have no enough space for the next name stack data */
330bf215546Sopenharmony_ci   return s->ResultOffset >= MAX_NAME_STACK_RESULT_NUM * 3 * sizeof(GLuint) ||
331bf215546Sopenharmony_ci      s->SaveBufferTail >= NAME_STACK_BUFFER_SIZE - (MAX_NAME_STACK_DEPTH + 3) * sizeof(GLuint);
332bf215546Sopenharmony_ci}
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_cistatic void
335bf215546Sopenharmony_ciupdate_hit_record(struct gl_context *ctx)
336bf215546Sopenharmony_ci{
337bf215546Sopenharmony_ci   struct gl_selection *s = &ctx->Select;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci   if (ctx->Const.HardwareAcceleratedSelect) {
340bf215546Sopenharmony_ci      if (!s->SavedStackNum)
341bf215546Sopenharmony_ci         return;
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_ci      unsigned size = s->ResultOffset;
344bf215546Sopenharmony_ci      GLuint *result = size ? alloca(size) : NULL;
345bf215546Sopenharmony_ci      _mesa_bufferobj_get_subdata(ctx, 0, size, result, s->Result);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci      unsigned index = 0;
348bf215546Sopenharmony_ci      unsigned *save = s->SaveBuffer;
349bf215546Sopenharmony_ci      for (int i = 0; i < s->SavedStackNum; i++) {
350bf215546Sopenharmony_ci         uint8_t *metadata = (uint8_t *)(save++);
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci         unsigned zmin, zmax;
353bf215546Sopenharmony_ci         bool cpu_hit = !!metadata[0];
354bf215546Sopenharmony_ci         if (cpu_hit) {
355bf215546Sopenharmony_ci            /* map [0, 1] to [0, UINT_MAX]*/
356bf215546Sopenharmony_ci            zmin = (unsigned) ((float)(~0u) * *(float *)(save++));
357bf215546Sopenharmony_ci            zmax = (unsigned) ((float)(~0u) * *(float *)(save++));
358bf215546Sopenharmony_ci         } else {
359bf215546Sopenharmony_ci            zmin = ~0u;
360bf215546Sopenharmony_ci            zmax = 0;
361bf215546Sopenharmony_ci         }
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci         bool gpu_hit = false;
364bf215546Sopenharmony_ci         if (metadata[1]) {
365bf215546Sopenharmony_ci            gpu_hit = !!result[index];
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci            if (gpu_hit) {
368bf215546Sopenharmony_ci               zmin = MIN2(zmin, result[index + 1]);
369bf215546Sopenharmony_ci               zmax = MAX2(zmax, result[index + 2]);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci               /* reset data */
372bf215546Sopenharmony_ci               result[index]     = 0;          /* hit */
373bf215546Sopenharmony_ci               result[index + 1] = 0xffffffff; /* minz */
374bf215546Sopenharmony_ci               result[index + 2] = 0;          /* maxz */
375bf215546Sopenharmony_ci            }
376bf215546Sopenharmony_ci            index += 3;
377bf215546Sopenharmony_ci         }
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci         int depth = metadata[2];
380bf215546Sopenharmony_ci         if (cpu_hit || gpu_hit) {
381bf215546Sopenharmony_ci            /* hit */
382bf215546Sopenharmony_ci            write_record(ctx, depth);
383bf215546Sopenharmony_ci            write_record(ctx, zmin);
384bf215546Sopenharmony_ci            write_record(ctx, zmax);
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci            for (int j = 0; j < depth; j++)
387bf215546Sopenharmony_ci               write_record(ctx, save[j]);
388bf215546Sopenharmony_ci            s->Hits++;
389bf215546Sopenharmony_ci         }
390bf215546Sopenharmony_ci         save += depth;
391bf215546Sopenharmony_ci      }
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci      /* reset result buffer */
394bf215546Sopenharmony_ci      _mesa_bufferobj_subdata(ctx, 0, size, result, s->Result);
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci      s->SaveBufferTail = 0;
397bf215546Sopenharmony_ci      s->SavedStackNum = 0;
398bf215546Sopenharmony_ci      s->ResultOffset = 0;
399bf215546Sopenharmony_ci   } else {
400bf215546Sopenharmony_ci      if (!s->HitFlag)
401bf215546Sopenharmony_ci         return;
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci      /* HitMinZ and HitMaxZ are in [0,1].  Multiply these values by */
404bf215546Sopenharmony_ci      /* 2^32-1 and round to nearest unsigned integer. */
405bf215546Sopenharmony_ci      GLuint zscale = (~0u);
406bf215546Sopenharmony_ci      GLuint zmin = (GLuint) ((GLfloat) zscale * s->HitMinZ);
407bf215546Sopenharmony_ci      GLuint zmax = (GLuint) ((GLfloat) zscale * s->HitMaxZ);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci      write_record(ctx, s->NameStackDepth);
410bf215546Sopenharmony_ci      write_record(ctx, zmin);
411bf215546Sopenharmony_ci      write_record(ctx, zmax);
412bf215546Sopenharmony_ci      for (int i = 0; i < s->NameStackDepth; i++)
413bf215546Sopenharmony_ci         write_record(ctx, s->NameStack[i]);
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci      s->HitFlag = GL_FALSE;
416bf215546Sopenharmony_ci      s->HitMinZ = 1.0;
417bf215546Sopenharmony_ci      s->HitMaxZ = -1.0;
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci      s->Hits++;
420bf215546Sopenharmony_ci   }
421bf215546Sopenharmony_ci}
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_cistatic void
424bf215546Sopenharmony_cireset_name_stack_to_empty(struct gl_context *ctx)
425bf215546Sopenharmony_ci{
426bf215546Sopenharmony_ci   struct gl_selection *s = &ctx->Select;
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   s->NameStackDepth = 0;
429bf215546Sopenharmony_ci   s->HitFlag = GL_FALSE;
430bf215546Sopenharmony_ci   s->HitMinZ = 1.0;
431bf215546Sopenharmony_ci   s->HitMaxZ = 0.0;
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   if (ctx->Const.HardwareAcceleratedSelect) {
434bf215546Sopenharmony_ci      s->SaveBufferTail = 0;
435bf215546Sopenharmony_ci      s->SavedStackNum = 0;
436bf215546Sopenharmony_ci      s->ResultUsed = GL_FALSE;
437bf215546Sopenharmony_ci      s->ResultOffset = 0;
438bf215546Sopenharmony_ci   }
439bf215546Sopenharmony_ci}
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci/**
442bf215546Sopenharmony_ci * Initialize the name stack.
443bf215546Sopenharmony_ci */
444bf215546Sopenharmony_civoid GLAPIENTRY
445bf215546Sopenharmony_ci_mesa_InitNames( void )
446bf215546Sopenharmony_ci{
447bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   /* Calls to glInitNames while the render mode is not GL_SELECT are ignored. */
450bf215546Sopenharmony_ci   if (ctx->RenderMode != GL_SELECT)
451bf215546Sopenharmony_ci      return;
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
454bf215546Sopenharmony_ci
455bf215546Sopenharmony_ci   save_used_name_stack(ctx);
456bf215546Sopenharmony_ci   update_hit_record(ctx);
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   reset_name_stack_to_empty(ctx);
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   ctx->NewState |= _NEW_RENDERMODE;
461bf215546Sopenharmony_ci}
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci/**
465bf215546Sopenharmony_ci * Load the top-most name of the name stack.
466bf215546Sopenharmony_ci *
467bf215546Sopenharmony_ci * \param name name.
468bf215546Sopenharmony_ci */
469bf215546Sopenharmony_civoid GLAPIENTRY
470bf215546Sopenharmony_ci_mesa_LoadName( GLuint name )
471bf215546Sopenharmony_ci{
472bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   if (ctx->RenderMode != GL_SELECT) {
475bf215546Sopenharmony_ci      return;
476bf215546Sopenharmony_ci   }
477bf215546Sopenharmony_ci   if (ctx->Select.NameStackDepth == 0) {
478bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_OPERATION, "glLoadName" );
479bf215546Sopenharmony_ci      return;
480bf215546Sopenharmony_ci   }
481bf215546Sopenharmony_ci
482bf215546Sopenharmony_ci   if (!ctx->Const.HardwareAcceleratedSelect || save_used_name_stack(ctx)) {
483bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, 0);
484bf215546Sopenharmony_ci      update_hit_record(ctx);
485bf215546Sopenharmony_ci   }
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   ctx->Select.NameStack[ctx->Select.NameStackDepth-1] = name;
488bf215546Sopenharmony_ci   ctx->NewState |= _NEW_RENDERMODE;
489bf215546Sopenharmony_ci}
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci
492bf215546Sopenharmony_ci/**
493bf215546Sopenharmony_ci * Push a name into the name stack.
494bf215546Sopenharmony_ci *
495bf215546Sopenharmony_ci * \param name name.
496bf215546Sopenharmony_ci */
497bf215546Sopenharmony_civoid GLAPIENTRY
498bf215546Sopenharmony_ci_mesa_PushName( GLuint name )
499bf215546Sopenharmony_ci{
500bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci   if (ctx->RenderMode != GL_SELECT) {
503bf215546Sopenharmony_ci      return;
504bf215546Sopenharmony_ci   }
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   if (ctx->Select.NameStackDepth >= MAX_NAME_STACK_DEPTH) {
507bf215546Sopenharmony_ci      _mesa_error( ctx, GL_STACK_OVERFLOW, "glPushName" );
508bf215546Sopenharmony_ci      return;
509bf215546Sopenharmony_ci   }
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (!ctx->Const.HardwareAcceleratedSelect || save_used_name_stack(ctx)) {
512bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, 0);
513bf215546Sopenharmony_ci      update_hit_record(ctx);
514bf215546Sopenharmony_ci   }
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci   ctx->Select.NameStack[ctx->Select.NameStackDepth++] = name;
517bf215546Sopenharmony_ci   ctx->NewState |= _NEW_RENDERMODE;
518bf215546Sopenharmony_ci}
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci/**
522bf215546Sopenharmony_ci * Pop a name into the name stack.
523bf215546Sopenharmony_ci */
524bf215546Sopenharmony_civoid GLAPIENTRY
525bf215546Sopenharmony_ci_mesa_PopName( void )
526bf215546Sopenharmony_ci{
527bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci   if (ctx->RenderMode != GL_SELECT) {
530bf215546Sopenharmony_ci      return;
531bf215546Sopenharmony_ci   }
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci   if (ctx->Select.NameStackDepth == 0) {
534bf215546Sopenharmony_ci      _mesa_error( ctx, GL_STACK_UNDERFLOW, "glPopName" );
535bf215546Sopenharmony_ci      return;
536bf215546Sopenharmony_ci   }
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci   if (!ctx->Const.HardwareAcceleratedSelect || save_used_name_stack(ctx)) {
539bf215546Sopenharmony_ci      FLUSH_VERTICES(ctx, 0, 0);
540bf215546Sopenharmony_ci      update_hit_record(ctx);
541bf215546Sopenharmony_ci   }
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci   ctx->Select.NameStackDepth--;
544bf215546Sopenharmony_ci   ctx->NewState |= _NEW_RENDERMODE;
545bf215546Sopenharmony_ci}
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci/*@}*/
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci/**********************************************************************/
551bf215546Sopenharmony_ci/** \name Render Mode */
552bf215546Sopenharmony_ci/*@{*/
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci/**
555bf215546Sopenharmony_ci * Set rasterization mode.
556bf215546Sopenharmony_ci *
557bf215546Sopenharmony_ci * \param mode rasterization mode.
558bf215546Sopenharmony_ci *
559bf215546Sopenharmony_ci * \note this function can't be put in a display list.
560bf215546Sopenharmony_ci *
561bf215546Sopenharmony_ci * \sa glRenderMode().
562bf215546Sopenharmony_ci *
563bf215546Sopenharmony_ci * Flushes the vertices and do the necessary cleanup according to the previous
564bf215546Sopenharmony_ci * rasterization mode, such as writing the hit record or resent the select
565bf215546Sopenharmony_ci * buffer index when exiting the select mode. Updates
566bf215546Sopenharmony_ci * __struct gl_contextRec::RenderMode and notifies the driver via the
567bf215546Sopenharmony_ci * dd_function_table::RenderMode callback.
568bf215546Sopenharmony_ci */
569bf215546Sopenharmony_ciGLint GLAPIENTRY
570bf215546Sopenharmony_ci_mesa_RenderMode( GLenum mode )
571bf215546Sopenharmony_ci{
572bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
573bf215546Sopenharmony_ci   GLint result;
574bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0);
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
577bf215546Sopenharmony_ci      _mesa_debug(ctx, "glRenderMode %s\n", _mesa_enum_to_string(mode));
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, _NEW_RENDERMODE | _NEW_FF_VERT_PROGRAM |
580bf215546Sopenharmony_ci                  _NEW_FF_FRAG_PROGRAM, 0);
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci   switch (ctx->RenderMode) {
583bf215546Sopenharmony_ci      case GL_RENDER:
584bf215546Sopenharmony_ci	 result = 0;
585bf215546Sopenharmony_ci	 break;
586bf215546Sopenharmony_ci      case GL_SELECT:
587bf215546Sopenharmony_ci	 save_used_name_stack(ctx);
588bf215546Sopenharmony_ci	 update_hit_record(ctx);
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ci	 if (ctx->Select.BufferCount > ctx->Select.BufferSize) {
591bf215546Sopenharmony_ci	    /* overflow */
592bf215546Sopenharmony_ci#ifndef NDEBUG
593bf215546Sopenharmony_ci            _mesa_warning(ctx, "Feedback buffer overflow");
594bf215546Sopenharmony_ci#endif
595bf215546Sopenharmony_ci	    result = -1;
596bf215546Sopenharmony_ci	 }
597bf215546Sopenharmony_ci	 else {
598bf215546Sopenharmony_ci	    result = ctx->Select.Hits;
599bf215546Sopenharmony_ci	 }
600bf215546Sopenharmony_ci	 ctx->Select.BufferCount = 0;
601bf215546Sopenharmony_ci	 ctx->Select.Hits = 0;
602bf215546Sopenharmony_ci	 /* name stack should be in empty state after exiting GL_SELECT mode */
603bf215546Sopenharmony_ci	 reset_name_stack_to_empty(ctx);
604bf215546Sopenharmony_ci	 break;
605bf215546Sopenharmony_ci      case GL_FEEDBACK:
606bf215546Sopenharmony_ci	 if (ctx->Feedback.Count > ctx->Feedback.BufferSize) {
607bf215546Sopenharmony_ci	    /* overflow */
608bf215546Sopenharmony_ci	    result = -1;
609bf215546Sopenharmony_ci	 }
610bf215546Sopenharmony_ci	 else {
611bf215546Sopenharmony_ci	    result = ctx->Feedback.Count;
612bf215546Sopenharmony_ci	 }
613bf215546Sopenharmony_ci	 ctx->Feedback.Count = 0;
614bf215546Sopenharmony_ci	 break;
615bf215546Sopenharmony_ci      default:
616bf215546Sopenharmony_ci	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
617bf215546Sopenharmony_ci	 return 0;
618bf215546Sopenharmony_ci   }
619bf215546Sopenharmony_ci
620bf215546Sopenharmony_ci   switch (mode) {
621bf215546Sopenharmony_ci      case GL_RENDER:
622bf215546Sopenharmony_ci         break;
623bf215546Sopenharmony_ci      case GL_SELECT:
624bf215546Sopenharmony_ci	 if (ctx->Select.BufferSize==0) {
625bf215546Sopenharmony_ci	    /* haven't called glSelectBuffer yet */
626bf215546Sopenharmony_ci	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
627bf215546Sopenharmony_ci	 }
628bf215546Sopenharmony_ci	 alloc_select_resource(ctx);
629bf215546Sopenharmony_ci	 break;
630bf215546Sopenharmony_ci      case GL_FEEDBACK:
631bf215546Sopenharmony_ci	 if (ctx->Feedback.BufferSize==0) {
632bf215546Sopenharmony_ci	    /* haven't called glFeedbackBuffer yet */
633bf215546Sopenharmony_ci	    _mesa_error( ctx, GL_INVALID_OPERATION, "glRenderMode" );
634bf215546Sopenharmony_ci	 }
635bf215546Sopenharmony_ci	 break;
636bf215546Sopenharmony_ci      default:
637bf215546Sopenharmony_ci	 _mesa_error( ctx, GL_INVALID_ENUM, "glRenderMode" );
638bf215546Sopenharmony_ci	 return 0;
639bf215546Sopenharmony_ci   }
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci   st_RenderMode( ctx, mode );
642bf215546Sopenharmony_ci
643bf215546Sopenharmony_ci   /* finally update render mode to new one */
644bf215546Sopenharmony_ci   ctx->RenderMode = mode;
645bf215546Sopenharmony_ci
646bf215546Sopenharmony_ci   return result;
647bf215546Sopenharmony_ci}
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_ci/*@}*/
650bf215546Sopenharmony_ci
651bf215546Sopenharmony_ci
652bf215546Sopenharmony_ci/**********************************************************************/
653bf215546Sopenharmony_ci/** \name Initialization */
654bf215546Sopenharmony_ci/*@{*/
655bf215546Sopenharmony_ci
656bf215546Sopenharmony_ci/**
657bf215546Sopenharmony_ci * Initialize context feedback data.
658bf215546Sopenharmony_ci */
659bf215546Sopenharmony_civoid _mesa_init_feedback( struct gl_context * ctx )
660bf215546Sopenharmony_ci{
661bf215546Sopenharmony_ci   /* Feedback */
662bf215546Sopenharmony_ci   ctx->Feedback.Type = GL_2D;   /* TODO: verify */
663bf215546Sopenharmony_ci   ctx->Feedback.Buffer = NULL;
664bf215546Sopenharmony_ci   ctx->Feedback.BufferSize = 0;
665bf215546Sopenharmony_ci   ctx->Feedback.Count = 0;
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci   /* Selection/picking */
668bf215546Sopenharmony_ci   ctx->Select.Buffer = NULL;
669bf215546Sopenharmony_ci   ctx->Select.BufferSize = 0;
670bf215546Sopenharmony_ci   ctx->Select.BufferCount = 0;
671bf215546Sopenharmony_ci   ctx->Select.Hits = 0;
672bf215546Sopenharmony_ci   ctx->Select.NameStackDepth = 0;
673bf215546Sopenharmony_ci
674bf215546Sopenharmony_ci   /* Miscellaneous */
675bf215546Sopenharmony_ci   ctx->RenderMode = GL_RENDER;
676bf215546Sopenharmony_ci}
677bf215546Sopenharmony_ci
678bf215546Sopenharmony_civoid _mesa_free_feedback(struct gl_context * ctx)
679bf215546Sopenharmony_ci{
680bf215546Sopenharmony_ci   struct gl_selection *s = &ctx->Select;
681bf215546Sopenharmony_ci
682bf215546Sopenharmony_ci   free(s->SaveBuffer);
683bf215546Sopenharmony_ci   _mesa_reference_buffer_object(ctx, &s->Result, NULL);
684bf215546Sopenharmony_ci}
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci/*@}*/
687