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