/** * Allocate a renderbuffer for a an on-screen window (not a user-created * renderbuffer). The window system code determines the format. */ struct gl_renderbuffer * st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw) { struct st_renderbuffer *strb; strb = ST_CALLOC_STRUCT(st_renderbuffer); if (!strb) { _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer"); return NULL; } _mesa_init_renderbuffer(&strb->Base, 0); strb->Base.ClassID = 0x4242; /* just a unique value */ strb->Base.NumSamples = samples; strb->Base.Format = st_pipe_format_to_mesa_format(format); strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format); strb->software = sw; switch (format) { case PIPE_FORMAT_R8G8B8A8_UNORM: case PIPE_FORMAT_B8G8R8A8_UNORM: case PIPE_FORMAT_A8R8G8B8_UNORM: strb->Base.InternalFormat = GL_RGBA8; break; case PIPE_FORMAT_R8G8B8X8_UNORM: case PIPE_FORMAT_B8G8R8X8_UNORM: case PIPE_FORMAT_X8R8G8B8_UNORM: strb->Base.InternalFormat = GL_RGB8; break; case PIPE_FORMAT_B5G5R5A1_UNORM: strb->Base.InternalFormat = GL_RGB5_A1; break; case PIPE_FORMAT_B4G4R4A4_UNORM: strb->Base.InternalFormat = GL_RGBA4; break; case PIPE_FORMAT_B5G6R5_UNORM: strb->Base.InternalFormat = GL_RGB565; break; case PIPE_FORMAT_Z16_UNORM: strb->Base.InternalFormat = GL_DEPTH_COMPONENT16; break; case PIPE_FORMAT_Z32_UNORM: strb->Base.InternalFormat = GL_DEPTH_COMPONENT32; break; case PIPE_FORMAT_Z24_UNORM_S8_UINT: case PIPE_FORMAT_S8_UINT_Z24_UNORM: strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT; break; case PIPE_FORMAT_Z24X8_UNORM: case PIPE_FORMAT_X8Z24_UNORM: strb->Base.InternalFormat = GL_DEPTH_COMPONENT24; break; case PIPE_FORMAT_S8_UINT: strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT; break; case PIPE_FORMAT_R16G16B16A16_SNORM: /* accum buffer */ strb->Base.InternalFormat = GL_RGBA16_SNORM; break; case PIPE_FORMAT_R16G16B16A16_UNORM: strb->Base.InternalFormat = GL_RGBA16; break; case PIPE_FORMAT_R8_UNORM: strb->Base.InternalFormat = GL_R8; break; case PIPE_FORMAT_R8G8_UNORM: strb->Base.InternalFormat = GL_RG8; break; case PIPE_FORMAT_R16_UNORM: strb->Base.InternalFormat = GL_R16; break; case PIPE_FORMAT_R16G16_UNORM: strb->Base.InternalFormat = GL_RG16; break; case PIPE_FORMAT_R32G32B32A32_FLOAT: strb->Base.InternalFormat = GL_RGBA32F; break; case PIPE_FORMAT_R16G16B16A16_FLOAT: strb->Base.InternalFormat = GL_RGBA16F; break; default: _mesa_problem(NULL, "Unexpected format %s in st_new_renderbuffer_fb", util_format_name(format)); free(strb); return NULL; } /* st-specific methods */ strb->Base.Delete = st_renderbuffer_delete; strb->Base.AllocStorage = st_renderbuffer_alloc_storage; /* surface is allocated in st_renderbuffer_alloc_storage() */ strb->surface = NULL; return &strb->Base; }
/** * Apply the given stencil operator to the array of stencil values. * Don't touch stencil[i] if mask[i] is zero. * Input: n - size of stencil array * oper - the stencil buffer operator * face - 0 or 1 for front or back face operation * stencil - array of stencil values * mask - array [n] of flag: 1=apply operator, 0=don't apply operator * Output: stencil - modified values */ static void apply_stencil_op( const GLcontext *ctx, GLenum oper, GLuint face, GLuint n, GLstencil stencil[], const GLubyte mask[] ) { const GLstencil ref = ctx->Stencil.Ref[face]; const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; const GLstencil invmask = (GLstencil) (~wrtmask); GLuint i; switch (oper) { case GL_KEEP: /* do nothing */ break; case GL_ZERO: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = 0; } } } else { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = (GLstencil) (stencil[i] & invmask); } } } break; case GL_REPLACE: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i] = ref; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s ) | (wrtmask & ref)); } } } break; case GL_INCR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; if (s < STENCIL_MAX) { stencil[i] = (GLstencil) (s+1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { /* VERIFY logic of adding 1 to a write-masked value */ GLstencil s = stencil[i]; if (s < STENCIL_MAX) { stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); } } } } break; case GL_DECR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; if (s>0) { stencil[i] = (GLstencil) (s-1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { /* VERIFY logic of subtracting 1 to a write-masked value */ GLstencil s = stencil[i]; if (s>0) { stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); } } } } break; case GL_INCR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i]++; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s+1))); } } } break; case GL_DECR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { stencil[i]--; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & (s-1))); } } } break; case GL_INVERT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ~s; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil s = stencil[i]; stencil[i] = (GLstencil) ((invmask & s) | (wrtmask & ~s)); } } } break; default: _mesa_problem(ctx, "Bad stencil op in apply_stencil_op"); } }
/** * Allocate a new driRenderbuffer object. * Individual drivers are free to implement different versions of * this function. * * At this time, this function can only be used for window-system * renderbuffers, not user-created RBOs. * * \param format Either GL_RGBA, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, * GL_DEPTH_COMPONENT32, or GL_STENCIL_INDEX8_EXT (for now). * \param addr address in main memory of the buffer. Probably a memory * mapped region. * \param cpp chars or bytes per pixel * \param offset start of renderbuffer with respect to start of framebuffer * \param pitch pixels per row */ driRenderbuffer * driNewRenderbuffer(gl_format format, GLvoid *addr, GLint cpp, GLint offset, GLint pitch, __DRIdrawablePrivate *dPriv) { driRenderbuffer *drb; assert(format == GL_RGBA || format == GL_RGB5 || format == GL_RGBA8 || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24 || format == GL_DEPTH_COMPONENT32 || format == GL_STENCIL_INDEX8_EXT); assert(cpp > 0); assert(pitch > 0); drb = _mesa_calloc(sizeof(driRenderbuffer)); if (drb) { const GLuint name = 0; _mesa_init_renderbuffer(&drb->Base, name); /* Make sure we're using a null-valued GetPointer routine */ assert(drb->Base.GetPointer(NULL, &drb->Base, 0, 0) == NULL); switch (format) { case MESA_FORMAT_ARGB8888: if (cpp == 2) { /* override format */ format = MESA_FORMAT_RGB565; } drb->Base.DataType = GL_UNSIGNED_BYTE; break; case MESA_FORMAT_Z16: /* Depth */ /* we always Get/Put 32-bit Z values */ drb->Base.DataType = GL_UNSIGNED_INT; assert(cpp == 2); break; case MESA_FORMAT_Z32: /* Depth */ /* we always Get/Put 32-bit Z values */ drb->Base.DataType = GL_UNSIGNED_INT; assert(cpp == 4); break; case MESA_FORMAT_Z24_S8: drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; assert(cpp == 4); break; case MESA_FORMAT_S8_Z24: drb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; assert(cpp == 4); break; case MESA_FORMAT_S8: /* Stencil */ drb->Base.DataType = GL_UNSIGNED_BYTE; break; default: _mesa_problem(NULL, "Bad format 0x%x in driNewRenderbuffer", format); return NULL; } drb->Base.Format = format; drb->Base.InternalFormat = drb->Base._BaseFormat = _mesa_get_format_base_format(format); drb->Base.AllocStorage = driRenderbufferStorage; drb->Base.Delete = driDeleteRenderbuffer; drb->Base.Data = addr; /* DRI renderbuffer-specific fields: */ drb->dPriv = dPriv; drb->offset = offset; drb->pitch = pitch; drb->cpp = cpp; /* may be changed if page flipping is active: */ drb->flippedOffset = offset; drb->flippedPitch = pitch; drb->flippedData = addr; } return drb; }
/** * Append instructions to implement fog * * The \c fragment.fogcoord input is used to compute the fog blend factor. * * \param ctx The GL context * \param fprog Fragment program that fog instructions will be appended to. * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. * \param saturate True if writes to color outputs should be clamped to [0, 1] * * \note * This function sets \c VARYING_BIT_FOGC in \c fprog->Base.InputsRead. * * \todo With a little work, this function could be adapted to add fog code * to vertex programs too. */ void _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog, GLenum fog_mode, GLboolean saturate) { static const gl_state_index fogPStateOpt[STATE_LENGTH] = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; static const gl_state_index fogColorState[STATE_LENGTH] = { STATE_FOG_COLOR, 0, 0, 0, 0}; struct prog_instruction *newInst, *inst; const GLuint origLen = fprog->Base.NumInstructions; const GLuint newLen = origLen + 5; GLuint i; GLint fogPRefOpt, fogColorRef; /* state references */ GLuint colorTemp, fogFactorTemp; /* temporary registerss */ if (fog_mode == GL_NONE) { _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" " with fog_mode == GL_NONE"); return; } if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) { /* program doesn't output color, so nothing to do */ return; } /* Alloc storage for new instructions */ newInst = _mesa_alloc_instructions(newLen); if (!newInst) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glProgramString(inserting fog_option code)"); return; } /* Copy orig instructions into new instruction buffer */ _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen); /* PARAM fogParamsRefOpt = internal optimized fog params; */ fogPRefOpt = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt); /* PARAM fogColorRef = state.fog.color; */ fogColorRef = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState); /* TEMP colorTemp; */ colorTemp = fprog->Base.NumTemporaries++; /* TEMP fogFactorTemp; */ fogFactorTemp = fprog->Base.NumTemporaries++; /* Scan program to find where result.color is written */ inst = newInst; for (i = 0; i < fprog->Base.NumInstructions; i++) { if (inst->Opcode == OPCODE_END) break; if (inst->DstReg.File == PROGRAM_OUTPUT && inst->DstReg.Index == FRAG_RESULT_COLOR) { /* change the instruction to write to colorTemp w/ clamping */ inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = colorTemp; inst->SaturateMode = saturate; /* don't break (may be several writes to result.color) */ } inst++; } assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */ _mesa_init_instructions(inst, 5); /* emit instructions to compute fog blending factor */ /* this is always clamped to [0, 1] regardless of fragment clamping */ if (fog_mode == GL_LINEAR) { /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ inst->Opcode = OPCODE_MAD; inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = fogFactorTemp; inst->DstReg.WriteMask = WRITEMASK_X; inst->SrcReg[0].File = PROGRAM_INPUT; inst->SrcReg[0].Index = VARYING_SLOT_FOGC; inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; inst->SrcReg[1].File = PROGRAM_STATE_VAR; inst->SrcReg[1].Index = fogPRefOpt; inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; inst->SrcReg[2].File = PROGRAM_STATE_VAR; inst->SrcReg[2].Index = fogPRefOpt; inst->SrcReg[2].Swizzle = SWIZZLE_YYYY; inst->SaturateMode = SATURATE_ZERO_ONE; inst++; } else { ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2); /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ inst->Opcode = OPCODE_MUL; inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = fogFactorTemp; inst->DstReg.WriteMask = WRITEMASK_X; inst->SrcReg[0].File = PROGRAM_STATE_VAR; inst->SrcReg[0].Index = fogPRefOpt; inst->SrcReg[0].Swizzle = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; inst->SrcReg[1].File = PROGRAM_INPUT; inst->SrcReg[1].Index = VARYING_SLOT_FOGC; inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; inst++; if (fog_mode == GL_EXP2) { /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ inst->Opcode = OPCODE_MUL; inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = fogFactorTemp; inst->DstReg.WriteMask = WRITEMASK_X; inst->SrcReg[0].File = PROGRAM_TEMPORARY; inst->SrcReg[0].Index = fogFactorTemp; inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; inst->SrcReg[1].File = PROGRAM_TEMPORARY; inst->SrcReg[1].Index = fogFactorTemp; inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; inst++; } /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */ inst->Opcode = OPCODE_EX2; inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = fogFactorTemp; inst->DstReg.WriteMask = WRITEMASK_X; inst->SrcReg[0].File = PROGRAM_TEMPORARY; inst->SrcReg[0].Index = fogFactorTemp; inst->SrcReg[0].Negate = NEGATE_XYZW; inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; inst->SaturateMode = SATURATE_ZERO_ONE; inst++; } /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */ inst->Opcode = OPCODE_LRP; inst->DstReg.File = PROGRAM_OUTPUT; inst->DstReg.Index = FRAG_RESULT_COLOR; inst->DstReg.WriteMask = WRITEMASK_XYZ; inst->SrcReg[0].File = PROGRAM_TEMPORARY; inst->SrcReg[0].Index = fogFactorTemp; inst->SrcReg[0].Swizzle = SWIZZLE_XXXX; inst->SrcReg[1].File = PROGRAM_TEMPORARY; inst->SrcReg[1].Index = colorTemp; inst->SrcReg[1].Swizzle = SWIZZLE_NOOP; inst->SrcReg[2].File = PROGRAM_STATE_VAR; inst->SrcReg[2].Index = fogColorRef; inst->SrcReg[2].Swizzle = SWIZZLE_NOOP; inst++; /* MOV result.color.w, colorTemp.x; # copy alpha */ inst->Opcode = OPCODE_MOV; inst->DstReg.File = PROGRAM_OUTPUT; inst->DstReg.Index = FRAG_RESULT_COLOR; inst->DstReg.WriteMask = WRITEMASK_W; inst->SrcReg[0].File = PROGRAM_TEMPORARY; inst->SrcReg[0].Index = colorTemp; inst->SrcReg[0].Swizzle = SWIZZLE_NOOP; inst++; /* END; */ inst->Opcode = OPCODE_END; inst++; /* free old instructions */ _mesa_free_instructions(fprog->Base.Instructions, origLen); /* install new instructions */ fprog->Base.Instructions = newInst; fprog->Base.NumInstructions = inst - newInst; fprog->Base.InputsRead |= VARYING_BIT_FOGC; assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR)); }
/** * Apply the given stencil operator for each pixel in the array whose * mask flag is set. * \note This is for software stencil buffers only. * Input: n - number of pixels in the span * x, y - array of [n] pixels * operator - the stencil buffer operator * mask - array [n] of flag: 1=apply operator, 0=don't apply operator */ static void apply_stencil_op_to_pixels( const GLcontext *ctx, GLuint n, const GLint x[], const GLint y[], GLenum oper, GLuint face, const GLubyte mask[] ) { const GLstencil ref = ctx->Stencil.Ref[face]; const GLstencil wrtmask = ctx->Stencil.WriteMask[face]; const GLstencil invmask = (GLstencil) (~wrtmask); GLuint i; ASSERT(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); /* software stencil buffer only! */ switch (oper) { case GL_KEEP: /* do nothing */ break; case GL_ZERO: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = 0; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (invmask & *sptr); } } } break; case GL_REPLACE: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = ref; } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr ) | (wrtmask & ref)); } } } break; case GL_INCR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr < STENCIL_MAX) { *sptr = (GLstencil) (*sptr + 1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr < STENCIL_MAX) { *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); } } } } break; case GL_DECR: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr>0) { *sptr = (GLstencil) (*sptr - 1); } } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); if (*sptr>0) { *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); } } } } break; case GL_INCR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (*sptr + 1); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr+1))); } } } break; case GL_DECR_WRAP_EXT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (*sptr - 1); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & (*sptr-1))); } } } break; case GL_INVERT: if (invmask==0) { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) (~*sptr); } } } else { for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS( x[i], y[i] ); *sptr = (GLstencil) ((invmask & *sptr) | (wrtmask & ~*sptr)); } } } break; default: _mesa_problem(ctx, "Bad stencilop in apply_stencil_op_to_pixels"); } }
static const unsigned * brw_cs_emit(struct brw_context *brw, void *mem_ctx, const struct brw_cs_prog_key *key, struct brw_cs_prog_data *prog_data, struct gl_compute_program *cp, struct gl_shader_program *prog, unsigned *final_assembly_size) { bool start_busy = false; double start_time = 0; if (unlikely(brw->perf_debug)) { start_busy = (brw->batch.last_bo && drm_intel_bo_busy(brw->batch.last_bo)); start_time = get_time(); } struct brw_shader *shader = (struct brw_shader *) prog->_LinkedShaders[MESA_SHADER_COMPUTE]; if (unlikely(INTEL_DEBUG & DEBUG_CS)) brw_dump_ir("compute", prog, &shader->base, &cp->Base); prog_data->local_size[0] = cp->LocalSize[0]; prog_data->local_size[1] = cp->LocalSize[1]; prog_data->local_size[2] = cp->LocalSize[2]; unsigned local_workgroup_size = cp->LocalSize[0] * cp->LocalSize[1] * cp->LocalSize[2]; cfg_t *cfg = NULL; const char *fail_msg = NULL; int st_index = -1; if (INTEL_DEBUG & DEBUG_SHADER_TIME) st_index = brw_get_shader_time_index(brw, prog, &cp->Base, ST_CS); /* Now the main event: Visit the shader IR and generate our CS IR for it. */ fs_visitor v8(brw->intelScreen->compiler, brw, mem_ctx, MESA_SHADER_COMPUTE, key, &prog_data->base, prog, &cp->Base, 8, st_index); if (!v8.run_cs()) { fail_msg = v8.fail_msg; } else if (local_workgroup_size <= 8 * brw->max_cs_threads) { cfg = v8.cfg; prog_data->simd_size = 8; } fs_visitor v16(brw->intelScreen->compiler, brw, mem_ctx, MESA_SHADER_COMPUTE, key, &prog_data->base, prog, &cp->Base, 16, st_index); if (likely(!(INTEL_DEBUG & DEBUG_NO16)) && !fail_msg && !v8.simd16_unsupported && local_workgroup_size <= 16 * brw->max_cs_threads) { /* Try a SIMD16 compile */ v16.import_uniforms(&v8); if (!v16.run_cs()) { perf_debug("SIMD16 shader failed to compile: %s", v16.fail_msg); if (!cfg) { fail_msg = "Couldn't generate SIMD16 program and not " "enough threads for SIMD8"; } } else { cfg = v16.cfg; prog_data->simd_size = 16; } } if (unlikely(cfg == NULL)) { assert(fail_msg); prog->LinkStatus = false; ralloc_strcat(&prog->InfoLog, fail_msg); _mesa_problem(NULL, "Failed to compile compute shader: %s\n", fail_msg); return NULL; } fs_generator g(brw->intelScreen->compiler, brw, mem_ctx, (void*) key, &prog_data->base, &cp->Base, v8.promoted_constants, v8.runtime_check_aads_emit, "CS"); if (INTEL_DEBUG & DEBUG_CS) { char *name = ralloc_asprintf(mem_ctx, "%s compute shader %d", prog->Label ? prog->Label : "unnamed", prog->Name); g.enable_debug(name); } g.generate_code(cfg, prog_data->simd_size); if (unlikely(brw->perf_debug) && shader) { if (shader->compiled_once) { _mesa_problem(&brw->ctx, "CS programs shouldn't need recompiles"); } shader->compiled_once = true; if (start_busy && !drm_intel_bo_busy(brw->batch.last_bo)) { perf_debug("CS compile took %.03f ms and stalled the GPU\n", (get_time() - start_time) * 1000); } } return g.get_assembly(final_assembly_size); }
/** * Convert "classic" texture environment to ARB_texture_env_combine style * environments. * * \param state texture_env_combine state vector to be filled-in. * \param mode Classic texture environment mode (i.e., \c GL_REPLACE, * \c GL_BLEND, \c GL_DECAL, etc.). * \param texBaseFormat Base format of the texture associated with the * texture unit. */ static void calculate_derived_texenv( struct gl_tex_env_combine_state *state, GLenum mode, GLenum texBaseFormat ) { GLenum mode_rgb; GLenum mode_a; *state = default_combine_state; switch (texBaseFormat) { case GL_ALPHA: state->SourceRGB[0] = GL_PREVIOUS; break; case GL_LUMINANCE_ALPHA: case GL_INTENSITY: case GL_RGBA: break; case GL_LUMINANCE: case GL_RED: case GL_RG: case GL_RGB: case GL_YCBCR_MESA: state->SourceA[0] = GL_PREVIOUS; break; default: _mesa_problem(NULL, "Invalid texBaseFormat 0x%x in calculate_derived_texenv", texBaseFormat); return; } if (mode == GL_REPLACE_EXT) mode = GL_REPLACE; switch (mode) { case GL_REPLACE: case GL_MODULATE: mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : mode; mode_a = mode; break; case GL_DECAL: mode_rgb = GL_INTERPOLATE; mode_a = GL_REPLACE; state->SourceA[0] = GL_PREVIOUS; /* Having alpha / luminance / intensity textures replace using the * incoming fragment color matches the definition in NV_texture_shader. * The 1.5 spec simply marks these as "undefined". */ switch (texBaseFormat) { case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: case GL_INTENSITY: state->SourceRGB[0] = GL_PREVIOUS; break; case GL_RED: case GL_RG: case GL_RGB: case GL_YCBCR_MESA: mode_rgb = GL_REPLACE; break; case GL_RGBA: state->SourceRGB[2] = GL_TEXTURE; break; } break; case GL_BLEND: mode_rgb = GL_INTERPOLATE; mode_a = GL_MODULATE; switch (texBaseFormat) { case GL_ALPHA: mode_rgb = GL_REPLACE; break; case GL_INTENSITY: mode_a = GL_INTERPOLATE; state->SourceA[0] = GL_CONSTANT; state->OperandA[2] = GL_SRC_ALPHA; /* FALLTHROUGH */ case GL_LUMINANCE: case GL_RED: case GL_RG: case GL_RGB: case GL_LUMINANCE_ALPHA: case GL_RGBA: case GL_YCBCR_MESA: state->SourceRGB[2] = GL_TEXTURE; state->SourceA[2] = GL_TEXTURE; state->SourceRGB[0] = GL_CONSTANT; state->OperandRGB[2] = GL_SRC_COLOR; break; } break; case GL_ADD: mode_rgb = (texBaseFormat == GL_ALPHA) ? GL_REPLACE : GL_ADD; mode_a = (texBaseFormat == GL_INTENSITY) ? GL_ADD : GL_MODULATE; break; default: _mesa_problem(NULL, "Invalid texture env mode 0x%x in calculate_derived_texenv", mode); return; } state->ModeRGB = (state->SourceRGB[0] != GL_PREVIOUS) ? mode_rgb : GL_REPLACE; state->ModeA = (state->SourceA[0] != GL_PREVIOUS) ? mode_a : GL_REPLACE; }
/** * Clear the stencil buffer. If the buffer is a combined * depth+stencil buffer, only the stencil bits will be touched. */ void _swrast_clear_stencil_buffer(struct gl_context *ctx) { struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits; const GLuint writeMask = ctx->Stencil.WriteMask[0]; const GLuint stencilMax = (1 << stencilBits) - 1; GLint x, y, width, height; GLubyte *map; GLint rowStride, i, j; GLbitfield mapMode; if (!rb || writeMask == 0) return; /* compute region to clear */ x = ctx->DrawBuffer->_Xmin; y = ctx->DrawBuffer->_Ymin; width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; mapMode = GL_MAP_WRITE_BIT; if ((writeMask & stencilMax) != stencilMax) { /* need to mask stencil values */ mapMode |= GL_MAP_READ_BIT; } else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) { /* combined depth+stencil, need to mask Z values */ mapMode |= GL_MAP_READ_BIT; } ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, mapMode, &map, &rowStride); if (!map) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)"); return; } switch (rb->Format) { case MESA_FORMAT_S8: { GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff; GLubyte mask = (~writeMask) & 0xff; if (mask != 0) { /* masked clear */ for (i = 0; i < height; i++) { GLubyte *row = map; for (j = 0; j < width; j++) { row[j] = (row[j] & mask) | clear; } map += rowStride; } } else if (rowStride == width) { /* clear whole buffer */ memset(map, clear, width * height); } else { /* clear scissored */ for (i = 0; i < height; i++) { memset(map, clear, width); map += rowStride; } } } break; case MESA_FORMAT_S8_Z24: { GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24; GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff; for (i = 0; i < height; i++) { GLuint *row = (GLuint *) map; for (j = 0; j < width; j++) { row[j] = (row[j] & mask) | clear; } map += rowStride; } } break; case MESA_FORMAT_Z24_S8: { GLuint clear = ctx->Stencil.Clear & writeMask & 0xff; GLuint mask = 0xffffff00 | ((~writeMask) & 0xff); for (i = 0; i < height; i++) { GLuint *row = (GLuint *) map; for (j = 0; j < width; j++) { row[j] = (row[j] & mask) | clear; } map += rowStride; } } break; default: _mesa_problem(ctx, "Unexpected stencil buffer format %s" " in _swrast_clear_stencil_buffer()", _mesa_get_format_name(rb->Format)); } ctx->Driver.UnmapRenderbuffer(ctx, rb); }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_resource *dst_texture; struct pipe_blit_info blit; unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ); struct pipe_transfer *tex_xfer; ubyte *map; /* create temp / dest surface */ if (!util_create_rgba_texture(pipe, width, height, bind, &dst_texture)) { _mesa_problem(ctx, "util_create_rgba_texture() failed " "in decompress_with_blit()"); return; } blit.src.resource = stObj->pt; blit.src.level = texImage->Level; blit.src.format = util_format_linear(stObj->pt->format); blit.dst.resource = dst_texture; blit.dst.level = 0; blit.dst.format = dst_texture->format; blit.src.box.x = blit.dst.box.x = 0; blit.src.box.y = blit.dst.box.y = 0; blit.src.box.z = 0; /* XXX compressed array textures? */ blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; /* blit/render/decompress */ st->pipe->blit(st->pipe, &blit); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); map = pipe_transfer_map(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height, &tex_xfer); if (!map) { goto end; } /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); /* map the dst_surface so we can read from it */ GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: if (map) pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe_resource_reference(&dst_texture, NULL); }
/** * Check if the given register index is valid (doesn't exceed implementation- * dependent limits). * \return GL_TRUE if OK, GL_FALSE if bad index */ GLboolean _mesa_valid_register_index(const struct gl_context *ctx, gl_shader_type shaderType, gl_register_file file, GLint index) { const struct gl_program_constants *c; switch (shaderType) { case MESA_SHADER_VERTEX: c = &ctx->Const.VertexProgram; break; case MESA_SHADER_FRAGMENT: c = &ctx->Const.FragmentProgram; break; case MESA_SHADER_GEOMETRY: c = &ctx->Const.GeometryProgram; break; default: _mesa_problem(ctx, "unexpected shader type in _mesa_valid_register_index()"); return GL_FALSE; } switch (file) { case PROGRAM_UNDEFINED: return GL_TRUE; /* XXX or maybe false? */ case PROGRAM_TEMPORARY: return index >= 0 && index < c->MaxTemps; case PROGRAM_ENV_PARAM: return index >= 0 && index < c->MaxEnvParams; case PROGRAM_LOCAL_PARAM: return index >= 0 && index < c->MaxLocalParams; case PROGRAM_NAMED_PARAM: return index >= 0 && index < c->MaxParameters; case PROGRAM_UNIFORM: case PROGRAM_STATE_VAR: /* aka constant buffer */ return index >= 0 && index < c->MaxUniformComponents / 4; case PROGRAM_CONSTANT: /* constant buffer w/ possible relative negative addressing */ return (index > (int) c->MaxUniformComponents / -4 && index < c->MaxUniformComponents / 4); case PROGRAM_INPUT: if (index < 0) return GL_FALSE; switch (shaderType) { case MESA_SHADER_VERTEX: return index < VERT_ATTRIB_GENERIC0 + c->MaxAttribs; case MESA_SHADER_FRAGMENT: return index < FRAG_ATTRIB_VAR0 + ctx->Const.MaxVarying; case MESA_SHADER_GEOMETRY: return index < GEOM_ATTRIB_VAR0 + ctx->Const.MaxVarying; default: return GL_FALSE; } case PROGRAM_OUTPUT: if (index < 0) return GL_FALSE; switch (shaderType) { case MESA_SHADER_VERTEX: return index < VERT_RESULT_VAR0 + ctx->Const.MaxVarying; case MESA_SHADER_FRAGMENT: return index < FRAG_RESULT_DATA0 + ctx->Const.MaxDrawBuffers; case MESA_SHADER_GEOMETRY: return index < GEOM_RESULT_VAR0 + ctx->Const.MaxVarying; default: return GL_FALSE; } case PROGRAM_ADDRESS: return index >= 0 && index < c->MaxAddressRegs; default: _mesa_problem(ctx, "unexpected register file in _mesa_valid_register_index()"); return GL_FALSE; } }
static int test_transform_function( transform_func func, int psize, int mtype, unsigned long *cycles ) { GLvector4f source[1], dest[1], ref[1]; GLmatrix mat[1]; GLfloat *m; int i, j; #ifdef RUN_DEBUG_BENCHMARK int cycle_i; /* the counter for the benchmarks we run */ #endif (void) cycles; if ( psize > 4 ) { _mesa_problem( NULL, "test_transform_function called with psize > 4\n" ); return 0; } mat->m = (GLfloat *) _mesa_align_malloc( 16 * sizeof(GLfloat), 16 ); mat->type = mtypes[mtype]; m = mat->m; ASSERT( ((long)m & 15) == 0 ); init_matrix( m ); for ( i = 0 ; i < 4 ; i++ ) { for ( j = 0 ; j < 4 ; j++ ) { switch ( templates[mtype][i * 4 + j] ) { case NIL: m[j * 4 + i] = 0.0; break; case ONE: m[j * 4 + i] = 1.0; break; case NEG: m[j * 4 + i] = -1.0; break; case VAR: break; default: ASSERT(0); return 0; } } } for ( i = 0 ; i < TEST_COUNT ; i++) { ASSIGN_4V( d[i], 0.0, 0.0, 0.0, 1.0 ); ASSIGN_4V( s[i], 0.0, 0.0, 0.0, 1.0 ); for ( j = 0 ; j < psize ; j++ ) s[i][j] = rnd(); } source->data = (GLfloat(*)[4])s; source->start = (GLfloat *)s; source->count = TEST_COUNT; source->stride = sizeof(s[0]); source->size = 4; source->flags = 0; dest->data = (GLfloat(*)[4])d; dest->start = (GLfloat *)d; dest->count = TEST_COUNT; dest->stride = sizeof(float[4]); dest->size = 0; dest->flags = 0; ref->data = (GLfloat(*)[4])r; ref->start = (GLfloat *)r; ref->count = TEST_COUNT; ref->stride = sizeof(float[4]); ref->size = 0; ref->flags = 0; ref_transform( ref, mat, source ); if ( mesa_profile ) { BEGIN_RACE( *cycles ); func( dest, mat->m, source ); END_RACE( *cycles ); } else { func( dest, mat->m, source ); } for ( i = 0 ; i < TEST_COUNT ; i++ ) { for ( j = 0 ; j < 4 ; j++ ) { if ( significand_match( d[i][j], r[i][j] ) < REQUIRED_PRECISION ) { printf("-----------------------------\n" ); printf("(i = %i, j = %i)\n", i, j ); printf("%f \t %f \t [diff = %e - %i bit missed]\n", d[i][0], r[i][0], r[i][0]-d[i][0], MAX_PRECISION - significand_match( d[i][0], r[i][0] ) ); printf("%f \t %f \t [diff = %e - %i bit missed]\n", d[i][1], r[i][1], r[i][1]-d[i][1], MAX_PRECISION - significand_match( d[i][1], r[i][1] ) ); printf("%f \t %f \t [diff = %e - %i bit missed]\n", d[i][2], r[i][2], r[i][2]-d[i][2], MAX_PRECISION - significand_match( d[i][2], r[i][2] ) ); printf("%f \t %f \t [diff = %e - %i bit missed]\n", d[i][3], r[i][3], r[i][3]-d[i][3], MAX_PRECISION - significand_match( d[i][3], r[i][3] ) ); return 0; } } } _mesa_align_free( mat->m ); return 1; }
/** * Combine two programs into one. Fix instructions so the outputs of * the first program go to the inputs of the second program. */ struct gl_program * _mesa_combine_programs(struct gl_context *ctx, const struct gl_program *progA, const struct gl_program *progB) { struct prog_instruction *newInst; struct gl_program *newProg; const GLuint lenA = progA->NumInstructions - 1; /* omit END instr */ const GLuint lenB = progB->NumInstructions; const GLuint numParamsA = _mesa_num_parameters(progA->Parameters); const GLuint newLength = lenA + lenB; GLboolean usedTemps[MAX_PROGRAM_TEMPS]; GLuint firstTemp = 0; GLbitfield inputsB; GLuint i; ASSERT(progA->Target == progB->Target); newInst = _mesa_alloc_instructions(newLength); if (!newInst) return GL_FALSE; _mesa_copy_instructions(newInst, progA->Instructions, lenA); _mesa_copy_instructions(newInst + lenA, progB->Instructions, lenB); /* adjust branch / instruction addresses for B's instructions */ for (i = 0; i < lenB; i++) { newInst[lenA + i].BranchTarget += lenA; } newProg = ctx->Driver.NewProgram(ctx, progA->Target, 0); newProg->Instructions = newInst; newProg->NumInstructions = newLength; /* find used temp regs (we may need new temps below) */ _mesa_find_used_registers(newProg, PROGRAM_TEMPORARY, usedTemps, MAX_PROGRAM_TEMPS); if (newProg->Target == GL_FRAGMENT_PROGRAM_ARB) { struct gl_fragment_program *fprogA, *fprogB, *newFprog; GLbitfield progB_inputsRead = progB->InputsRead; GLint progB_colorFile, progB_colorIndex; fprogA = (struct gl_fragment_program *) progA; fprogB = (struct gl_fragment_program *) progB; newFprog = (struct gl_fragment_program *) newProg; newFprog->UsesKill = fprogA->UsesKill || fprogB->UsesKill; /* We'll do a search and replace for instances * of progB_colorFile/progB_colorIndex below... */ progB_colorFile = PROGRAM_INPUT; progB_colorIndex = FRAG_ATTRIB_COL0; /* * The fragment program may get color from a state var rather than * a fragment input (vertex output) if it's constant. * See the texenvprogram.c code. * So, search the program's parameter list now to see if the program * gets color from a state var instead of a conventional fragment * input register. */ for (i = 0; i < progB->Parameters->NumParameters; i++) { struct gl_program_parameter *p = &progB->Parameters->Parameters[i]; if (p->Type == PROGRAM_STATE_VAR && p->StateIndexes[0] == STATE_INTERNAL && p->StateIndexes[1] == STATE_CURRENT_ATTRIB && (int) p->StateIndexes[2] == (int) VERT_ATTRIB_COLOR0) { progB_inputsRead |= FRAG_BIT_COL0; progB_colorFile = PROGRAM_STATE_VAR; progB_colorIndex = i; break; } } /* Connect color outputs of fprogA to color inputs of fprogB, via a * new temporary register. */ if ((progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) && (progB_inputsRead & FRAG_BIT_COL0)) { GLint tempReg = _mesa_find_free_register(usedTemps, MAX_PROGRAM_TEMPS, firstTemp); if (tempReg < 0) { _mesa_problem(ctx, "No free temp regs found in " "_mesa_combine_programs(), using 31"); tempReg = 31; } firstTemp = tempReg + 1; /* replace writes to result.color[0] with tempReg */ replace_registers(newInst, lenA, PROGRAM_OUTPUT, FRAG_RESULT_COLOR, PROGRAM_TEMPORARY, tempReg); /* replace reads from the input color with tempReg */ replace_registers(newInst + lenA, lenB, progB_colorFile, progB_colorIndex, /* search for */ PROGRAM_TEMPORARY, tempReg /* replace with */ ); } /* compute combined program's InputsRead */ inputsB = progB_inputsRead; if (progA->OutputsWritten & (1 << FRAG_RESULT_COLOR)) { inputsB &= ~(1 << FRAG_ATTRIB_COL0); } newProg->InputsRead = progA->InputsRead | inputsB; newProg->OutputsWritten = progB->OutputsWritten; newProg->SamplersUsed = progA->SamplersUsed | progB->SamplersUsed; } else { /* vertex program */ assert(0); /* XXX todo */ } /* * Merge parameters (uniforms, constants, etc) */ newProg->Parameters = _mesa_combine_parameter_lists(progA->Parameters, progB->Parameters); adjust_param_indexes(newInst + lenA, lenB, numParamsA); return newProg; }
/** * Return a copy of a program. * XXX Problem here if the program object is actually OO-derivation * made by a device driver. */ struct gl_program * _mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) { struct gl_program *clone; clone = ctx->Driver.NewProgram(ctx, prog->Target, prog->Id); if (!clone) return NULL; assert(clone->Target == prog->Target); assert(clone->RefCount == 1); clone->String = (GLubyte *) _mesa_strdup((char *) prog->String); clone->Format = prog->Format; clone->Instructions = _mesa_alloc_instructions(prog->NumInstructions); if (!clone->Instructions) { _mesa_reference_program(ctx, &clone, NULL); return NULL; } _mesa_copy_instructions(clone->Instructions, prog->Instructions, prog->NumInstructions); clone->InputsRead = prog->InputsRead; clone->OutputsWritten = prog->OutputsWritten; clone->SamplersUsed = prog->SamplersUsed; clone->ShadowSamplers = prog->ShadowSamplers; memcpy(clone->TexturesUsed, prog->TexturesUsed, sizeof(prog->TexturesUsed)); if (prog->Parameters) clone->Parameters = _mesa_clone_parameter_list(prog->Parameters); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); if (prog->Varying) clone->Varying = _mesa_clone_parameter_list(prog->Varying); if (prog->Attributes) clone->Attributes = _mesa_clone_parameter_list(prog->Attributes); memcpy(clone->LocalParams, prog->LocalParams, sizeof(clone->LocalParams)); clone->IndirectRegisterFiles = prog->IndirectRegisterFiles; clone->NumInstructions = prog->NumInstructions; clone->NumTemporaries = prog->NumTemporaries; clone->NumParameters = prog->NumParameters; clone->NumAttributes = prog->NumAttributes; clone->NumAddressRegs = prog->NumAddressRegs; clone->NumNativeInstructions = prog->NumNativeInstructions; clone->NumNativeTemporaries = prog->NumNativeTemporaries; clone->NumNativeParameters = prog->NumNativeParameters; clone->NumNativeAttributes = prog->NumNativeAttributes; clone->NumNativeAddressRegs = prog->NumNativeAddressRegs; clone->NumAluInstructions = prog->NumAluInstructions; clone->NumTexInstructions = prog->NumTexInstructions; clone->NumTexIndirections = prog->NumTexIndirections; clone->NumNativeAluInstructions = prog->NumNativeAluInstructions; clone->NumNativeTexInstructions = prog->NumNativeTexInstructions; clone->NumNativeTexIndirections = prog->NumNativeTexIndirections; switch (prog->Target) { case GL_VERTEX_PROGRAM_ARB: { const struct gl_vertex_program *vp = (const struct gl_vertex_program *) prog; struct gl_vertex_program *vpc = (struct gl_vertex_program *) clone; vpc->IsPositionInvariant = vp->IsPositionInvariant; vpc->IsNVProgram = vp->IsNVProgram; } break; case GL_FRAGMENT_PROGRAM_ARB: { const struct gl_fragment_program *fp = (const struct gl_fragment_program *) prog; struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; fpc->FogOption = fp->FogOption; fpc->UsesKill = fp->UsesKill; fpc->OriginUpperLeft = fp->OriginUpperLeft; fpc->PixelCenterInteger = fp->PixelCenterInteger; } break; case MESA_GEOMETRY_PROGRAM: { const struct gl_geometry_program *gp = (const struct gl_geometry_program *) prog; struct gl_geometry_program *gpc = (struct gl_geometry_program *) clone; gpc->VerticesOut = gp->VerticesOut; gpc->InputType = gp->InputType; gpc->OutputType = gp->OutputType; } break; default: _mesa_problem(NULL, "Unexpected target in _mesa_clone_program"); } return clone; }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); struct pipe_sampler_view *src_view; const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_surface *dst_surface; struct pipe_resource *dst_texture; struct pipe_transfer *tex_xfer; unsigned bind = (PIPE_BIND_RENDER_TARGET | /* util_blit may choose to render */ PIPE_BIND_TRANSFER_READ); /* create temp / dest surface */ if (!util_create_rgba_surface(pipe, width, height, bind, &dst_texture, &dst_surface)) { _mesa_problem(ctx, "util_create_rgba_surface() failed " "in decompress_with_blit()"); return; } /* Disable conditional rendering. */ if (st->render_condition) { pipe->render_condition(pipe, NULL, 0); } /* Create sampler view that limits fetches to the source mipmap level */ { struct pipe_sampler_view sv_temp; u_sampler_view_default_template(&sv_temp, stObj->pt, stObj->pt->format); sv_temp.format = util_format_linear(sv_temp.format); sv_temp.u.tex.first_level = sv_temp.u.tex.last_level = texImage->Level; src_view = pipe->create_sampler_view(pipe, stObj->pt, &sv_temp); if (!src_view) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage"); return; } } /* blit/render/decompress */ util_blit_pixels_tex(st->blit, src_view, /* pipe_resource (src) */ 0, 0, /* src x0, y0 */ width, height, /* src x1, y1 */ dst_surface, /* pipe_surface (dst) */ 0, 0, /* dst x0, y0 */ width, height, /* dst x1, y1 */ 0.0, /* z */ PIPE_TEX_MIPFILTER_NEAREST); /* Restore conditional rendering state. */ if (st->render_condition) { pipe->render_condition(pipe, st->render_condition, st->condition_mode); } /* map the dst_surface so we can read from it */ tex_xfer = pipe_get_transfer(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); ubyte *map = pipe_transfer_map(pipe, tex_xfer); GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = (GLfloat *) malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(pipe, tex_xfer, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe->transfer_destroy(pipe, tex_xfer); /* destroy the temp / dest surface */ util_destroy_rgba_surface(dst_texture, dst_surface); pipe_sampler_view_release(pipe, &src_view); }
/** * Helper for _mesa_meta_CopyTexSubImage1/2/3D() functions. * Have to be careful with locking and meta state for pixel transfer. */ static void copy_tex_sub_image(struct gl_context *ctx, GLuint dims, struct gl_texture_image *texImage, GLint xoffset, GLint yoffset, GLint zoffset, struct gl_renderbuffer *rb, GLint x, GLint y, GLsizei width, GLsizei height) { struct gl_texture_object *texObj = texImage->TexObject; const GLenum target = texObj->Target; GLenum format, type; GLint bpp; void *buf; /* Choose format/type for temporary image buffer */ format = _mesa_get_format_base_format(texImage->TexFormat); if (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA || format == GL_INTENSITY) { /* We don't want to use GL_LUMINANCE, GL_INTENSITY, etc. for the * temp image buffer because glReadPixels will do L=R+G+B which is * not what we want (should be L=R). */ format = GL_RGBA; } if (_mesa_is_format_integer_color(texImage->TexFormat)) { _mesa_problem(ctx, "unsupported integer color copyteximage"); return; } type = get_temp_image_type(ctx, format); bpp = _mesa_bytes_per_pixel(format, type); if (bpp <= 0) { _mesa_problem(ctx, "Bad bpp in meta copy_tex_sub_image()"); return; } /* * Alloc image buffer (XXX could use a PBO) */ buf = malloc(width * height * bpp); if (!buf) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%uD", dims); return; } _mesa_unlock_texture(ctx, texObj); /* need to unlock first */ /* * Read image from framebuffer (disable pixel transfer ops) */ _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE | MESA_META_PIXEL_TRANSFER); ctx->Driver.ReadPixels(ctx, x, y, width, height, format, type, &ctx->Pack, buf); _mesa_meta_end(ctx); _mesa_update_state(ctx); /* to update pixel transfer state */ /* * Store texture data (with pixel transfer ops) */ _mesa_meta_begin(ctx, MESA_META_PIXEL_STORE); if (target == GL_TEXTURE_1D) { ctx->Driver.TexSubImage1D(ctx, texImage, xoffset, width, format, type, buf, &ctx->Unpack); } else { ctx->Driver.TexSubImage2D(ctx, texImage, xoffset, yoffset, width, height, format, type, buf, &ctx->Unpack); } _mesa_meta_end(ctx); _mesa_lock_texture(ctx, texObj); /* re-lock */ free(buf); }
/** * Vert/Geom/Frag programs have per-context variants. Free all the * variants attached to the given program which match the given context. */ static void destroy_program_variants(struct st_context *st, struct gl_program *program) { if (!program) return; switch (program->Target) { case GL_VERTEX_PROGRAM_ARB: { struct st_vertex_program *stvp = (struct st_vertex_program *) program; struct st_vp_variant *vpv, **prevPtr = &stvp->variants; for (vpv = stvp->variants; vpv; ) { struct st_vp_variant *next = vpv->next; if (vpv->key.st == st) { /* unlink from list */ *prevPtr = next; /* destroy this variant */ delete_vp_variant(st, vpv); } else { prevPtr = &vpv->next; } vpv = next; } } break; case GL_FRAGMENT_PROGRAM_ARB: { struct st_fragment_program *stfp = (struct st_fragment_program *) program; struct st_fp_variant *fpv, **prevPtr = &stfp->variants; for (fpv = stfp->variants; fpv; ) { struct st_fp_variant *next = fpv->next; if (fpv->key.st == st) { /* unlink from list */ *prevPtr = next; /* destroy this variant */ delete_fp_variant(st, fpv); } else { prevPtr = &fpv->next; } fpv = next; } } break; case MESA_GEOMETRY_PROGRAM: { struct st_geometry_program *stgp = (struct st_geometry_program *) program; struct st_gp_variant *gpv, **prevPtr = &stgp->variants; for (gpv = stgp->variants; gpv; ) { struct st_gp_variant *next = gpv->next; if (gpv->key.st == st) { /* unlink from list */ *prevPtr = next; /* destroy this variant */ delete_gp_variant(st, gpv); } else { prevPtr = &gpv->next; } gpv = next; } } break; default: _mesa_problem(NULL, "Unexpected program target 0x%x in " "destroy_program_variants_cb()", program->Target); } }
/** * Generate assembly for a Vec4 IR instruction. * * \param instruction The Vec4 IR instruction to generate code for. * \param dst The destination register. * \param src An array of up to three source registers. */ void vec4_generator::generate_vec4_instruction(vec4_instruction *instruction, struct brw_reg dst, struct brw_reg *src) { vec4_instruction *inst = (vec4_instruction *) instruction; if (dst.width == BRW_WIDTH_4) { /* This happens in attribute fixups for "dual instanced" geometry * shaders, since they use attributes that are vec4's. Since the exec * width is only 4, it's essential that the caller set * force_writemask_all in order to make sure the instruction is executed * regardless of which channels are enabled. */ assert(inst->force_writemask_all); /* Fix up any <8;8,1> or <0;4,1> source registers to <4;4,1> to satisfy * the following register region restrictions (from Graphics BSpec: * 3D-Media-GPGPU Engine > EU Overview > Registers and Register Regions * > Register Region Restrictions) * * 1. ExecSize must be greater than or equal to Width. * * 2. If ExecSize = Width and HorzStride != 0, VertStride must be set * to Width * HorzStride." */ for (int i = 0; i < 3; i++) { if (src[i].file == BRW_GENERAL_REGISTER_FILE) src[i] = stride(src[i], 4, 4, 1); } } switch (inst->opcode) { case BRW_OPCODE_MOV: brw_MOV(p, dst, src[0]); break; case BRW_OPCODE_ADD: brw_ADD(p, dst, src[0], src[1]); break; case BRW_OPCODE_MUL: brw_MUL(p, dst, src[0], src[1]); break; case BRW_OPCODE_MACH: brw_set_acc_write_control(p, 1); brw_MACH(p, dst, src[0], src[1]); brw_set_acc_write_control(p, 0); break; case BRW_OPCODE_MAD: assert(brw->gen >= 6); brw_MAD(p, dst, src[0], src[1], src[2]); break; case BRW_OPCODE_FRC: brw_FRC(p, dst, src[0]); break; case BRW_OPCODE_RNDD: brw_RNDD(p, dst, src[0]); break; case BRW_OPCODE_RNDE: brw_RNDE(p, dst, src[0]); break; case BRW_OPCODE_RNDZ: brw_RNDZ(p, dst, src[0]); break; case BRW_OPCODE_AND: brw_AND(p, dst, src[0], src[1]); break; case BRW_OPCODE_OR: brw_OR(p, dst, src[0], src[1]); break; case BRW_OPCODE_XOR: brw_XOR(p, dst, src[0], src[1]); break; case BRW_OPCODE_NOT: brw_NOT(p, dst, src[0]); break; case BRW_OPCODE_ASR: brw_ASR(p, dst, src[0], src[1]); break; case BRW_OPCODE_SHR: brw_SHR(p, dst, src[0], src[1]); break; case BRW_OPCODE_SHL: brw_SHL(p, dst, src[0], src[1]); break; case BRW_OPCODE_CMP: brw_CMP(p, dst, inst->conditional_mod, src[0], src[1]); break; case BRW_OPCODE_SEL: brw_SEL(p, dst, src[0], src[1]); break; case BRW_OPCODE_DPH: brw_DPH(p, dst, src[0], src[1]); break; case BRW_OPCODE_DP4: brw_DP4(p, dst, src[0], src[1]); break; case BRW_OPCODE_DP3: brw_DP3(p, dst, src[0], src[1]); break; case BRW_OPCODE_DP2: brw_DP2(p, dst, src[0], src[1]); break; case BRW_OPCODE_F32TO16: assert(brw->gen >= 7); brw_F32TO16(p, dst, src[0]); break; case BRW_OPCODE_F16TO32: assert(brw->gen >= 7); brw_F16TO32(p, dst, src[0]); break; case BRW_OPCODE_LRP: assert(brw->gen >= 6); brw_LRP(p, dst, src[0], src[1], src[2]); break; case BRW_OPCODE_BFREV: assert(brw->gen >= 7); /* BFREV only supports UD type for src and dst. */ brw_BFREV(p, retype(dst, BRW_REGISTER_TYPE_UD), retype(src[0], BRW_REGISTER_TYPE_UD)); break; case BRW_OPCODE_FBH: assert(brw->gen >= 7); /* FBH only supports UD type for dst. */ brw_FBH(p, retype(dst, BRW_REGISTER_TYPE_UD), src[0]); break; case BRW_OPCODE_FBL: assert(brw->gen >= 7); /* FBL only supports UD type for dst. */ brw_FBL(p, retype(dst, BRW_REGISTER_TYPE_UD), src[0]); break; case BRW_OPCODE_CBIT: assert(brw->gen >= 7); /* CBIT only supports UD type for dst. */ brw_CBIT(p, retype(dst, BRW_REGISTER_TYPE_UD), src[0]); break; case BRW_OPCODE_ADDC: assert(brw->gen >= 7); brw_set_acc_write_control(p, 1); brw_ADDC(p, dst, src[0], src[1]); brw_set_acc_write_control(p, 0); break; case BRW_OPCODE_SUBB: assert(brw->gen >= 7); brw_set_acc_write_control(p, 1); brw_SUBB(p, dst, src[0], src[1]); brw_set_acc_write_control(p, 0); break; case BRW_OPCODE_BFE: assert(brw->gen >= 7); brw_BFE(p, dst, src[0], src[1], src[2]); break; case BRW_OPCODE_BFI1: assert(brw->gen >= 7); brw_BFI1(p, dst, src[0], src[1]); break; case BRW_OPCODE_BFI2: assert(brw->gen >= 7); brw_BFI2(p, dst, src[0], src[1], src[2]); break; case BRW_OPCODE_IF: if (inst->src[0].file != BAD_FILE) { /* The instruction has an embedded compare (only allowed on gen6) */ assert(brw->gen == 6); gen6_IF(p, inst->conditional_mod, src[0], src[1]); } else { struct brw_instruction *brw_inst = brw_IF(p, BRW_EXECUTE_8); brw_inst->header.predicate_control = inst->predicate; } break; case BRW_OPCODE_ELSE: brw_ELSE(p); break; case BRW_OPCODE_ENDIF: brw_ENDIF(p); break; case BRW_OPCODE_DO: brw_DO(p, BRW_EXECUTE_8); break; case BRW_OPCODE_BREAK: brw_BREAK(p); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case BRW_OPCODE_CONTINUE: /* FINISHME: We need to write the loop instruction support still. */ if (brw->gen >= 6) gen6_CONT(p); else brw_CONT(p); brw_set_predicate_control(p, BRW_PREDICATE_NONE); break; case BRW_OPCODE_WHILE: brw_WHILE(p); break; case SHADER_OPCODE_RCP: case SHADER_OPCODE_RSQ: case SHADER_OPCODE_SQRT: case SHADER_OPCODE_EXP2: case SHADER_OPCODE_LOG2: case SHADER_OPCODE_SIN: case SHADER_OPCODE_COS: if (brw->gen == 6) { generate_math1_gen6(inst, dst, src[0]); } else { /* Also works for Gen7. */ generate_math1_gen4(inst, dst, src[0]); } break; case SHADER_OPCODE_POW: case SHADER_OPCODE_INT_QUOTIENT: case SHADER_OPCODE_INT_REMAINDER: if (brw->gen >= 7) { generate_math2_gen7(inst, dst, src[0], src[1]); } else if (brw->gen == 6) { generate_math2_gen6(inst, dst, src[0], src[1]); } else { generate_math2_gen4(inst, dst, src[0], src[1]); } break; case SHADER_OPCODE_TEX: case SHADER_OPCODE_TXD: case SHADER_OPCODE_TXF: case SHADER_OPCODE_TXF_CMS: case SHADER_OPCODE_TXF_MCS: case SHADER_OPCODE_TXL: case SHADER_OPCODE_TXS: case SHADER_OPCODE_TG4: case SHADER_OPCODE_TG4_OFFSET: generate_tex(inst, dst, src[0]); break; case VS_OPCODE_URB_WRITE: generate_vs_urb_write(inst); break; case SHADER_OPCODE_GEN4_SCRATCH_READ: generate_scratch_read(inst, dst, src[0]); break; case SHADER_OPCODE_GEN4_SCRATCH_WRITE: generate_scratch_write(inst, dst, src[0], src[1]); break; case VS_OPCODE_PULL_CONSTANT_LOAD: generate_pull_constant_load(inst, dst, src[0], src[1]); break; case VS_OPCODE_PULL_CONSTANT_LOAD_GEN7: generate_pull_constant_load_gen7(inst, dst, src[0], src[1]); break; case GS_OPCODE_URB_WRITE: generate_gs_urb_write(inst); break; case GS_OPCODE_THREAD_END: generate_gs_thread_end(inst); break; case GS_OPCODE_SET_WRITE_OFFSET: generate_gs_set_write_offset(dst, src[0], src[1]); break; case GS_OPCODE_SET_VERTEX_COUNT: generate_gs_set_vertex_count(dst, src[0]); break; case GS_OPCODE_SET_DWORD_2_IMMED: generate_gs_set_dword_2_immed(dst, src[0]); break; case GS_OPCODE_PREPARE_CHANNEL_MASKS: generate_gs_prepare_channel_masks(dst); break; case GS_OPCODE_SET_CHANNEL_MASKS: generate_gs_set_channel_masks(dst, src[0]); break; case GS_OPCODE_GET_INSTANCE_ID: generate_gs_get_instance_id(dst); break; case SHADER_OPCODE_SHADER_TIME_ADD: brw_shader_time_add(p, src[0], prog_data->base.binding_table.shader_time_start); brw_mark_surface_used(&prog_data->base, prog_data->base.binding_table.shader_time_start); break; case SHADER_OPCODE_UNTYPED_ATOMIC: generate_untyped_atomic(inst, dst, src[0], src[1]); break; case SHADER_OPCODE_UNTYPED_SURFACE_READ: generate_untyped_surface_read(inst, dst, src[0]); break; case VS_OPCODE_UNPACK_FLAGS_SIMD4X2: generate_unpack_flags(inst, dst); break; default: if (inst->opcode < (int) ARRAY_SIZE(opcode_descs)) { _mesa_problem(&brw->ctx, "Unsupported opcode in `%s' in vec4\n", opcode_descs[inst->opcode].name); } else { _mesa_problem(&brw->ctx, "Unsupported opcode %d in vec4", inst->opcode); } abort(); } }
/** * Prepare the source or destination resource, including: * - Error checking * - Creating texture wrappers for renderbuffers * \param name the texture or renderbuffer name * \param target GL_TEXTURE target or GL_RENDERBUFFER. For the later, will * be changed to a compatible GL_TEXTURE target. * \param level mipmap level * \param tex_obj returns a pointer to a texture object * \param tex_image returns a pointer to a texture image * \param tmp_tex returns temporary texture object name * \return true if success, false if error */ static bool prepare_target(struct gl_context *ctx, GLuint name, GLenum *target, int level, struct gl_texture_object **tex_obj, struct gl_texture_image **tex_image, GLuint *tmp_tex, GLuint *width, GLuint *height, const char *dbg_prefix) { if (name == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %d)", dbg_prefix, name); return false; } /* * INVALID_ENUM is generated * * if either <srcTarget> or <dstTarget> * - is not RENDERBUFFER or a valid non-proxy texture target * - is TEXTURE_BUFFER, or * - is one of the cubemap face selectors described in table 3.17, */ switch (*target) { case GL_RENDERBUFFER: /* Not a texture target, but valid */ case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: /* These are all valid */ break; case GL_TEXTURE_EXTERNAL_OES: /* Only exists in ES */ case GL_TEXTURE_BUFFER: default: _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_enum_to_string(*target)); return false; } if (*target == GL_RENDERBUFFER) { struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); if (!rb) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } if (!rb->Name) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } if (level != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } if (rb->NumSamples > 1) *target = GL_TEXTURE_2D_MULTISAMPLE; else *target = GL_TEXTURE_2D; *tmp_tex = 0; _mesa_GenTextures(1, tmp_tex); if (*tmp_tex == 0) return false; /* Error already set by GenTextures */ _mesa_BindTexture(*target, *tmp_tex); *tex_obj = _mesa_lookup_texture(ctx, *tmp_tex); *tex_image = _mesa_get_tex_image(ctx, *tex_obj, *target, 0); *width = rb->Width; *height = rb->Height; if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, *tex_image)) { _mesa_problem(ctx, "Failed to create texture from renderbuffer"); return false; } if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) { rb->NeedsFinishRenderTexture = true; ctx->Driver.FinishRenderTexture(ctx, rb); } } else { *tex_obj = _mesa_lookup_texture(ctx, name); if (!*tex_obj) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sName = %u)", dbg_prefix, name); return false; } _mesa_test_texobj_completeness(ctx, *tex_obj); if (!(*tex_obj)->_BaseComplete || (level != 0 && !(*tex_obj)->_MipmapComplete)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyImageSubData(%sName incomplete)", dbg_prefix); return false; } if ((*tex_obj)->Target != *target) { _mesa_error(ctx, GL_INVALID_ENUM, "glCopyImageSubData(%sTarget = %s)", dbg_prefix, _mesa_enum_to_string(*target)); return false; } if (level < 0 || level >= MAX_TEXTURE_LEVELS) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %d)", dbg_prefix, level); return false; } *tex_image = _mesa_select_tex_image(*tex_obj, *target, level); if (!*tex_image) { _mesa_error(ctx, GL_INVALID_VALUE, "glCopyImageSubData(%sLevel = %u)", dbg_prefix, level); return false; } *width = (*tex_image)->Width; *height = (*tex_image)->Height; } return true; }
static void ctx_emit_cs(GLcontext *ctx, struct radeon_state_atom *atom) { r100ContextPtr r100 = R100_CONTEXT(ctx); BATCH_LOCALS(&r100->radeon); struct radeon_renderbuffer *rrb, *drb; uint32_t cbpitch = 0; uint32_t zbpitch = 0; uint32_t dwords = atom->check(ctx, atom); uint32_t depth_fmt; rrb = radeon_get_colorbuffer(&r100->radeon); if (!rrb || !rrb->bo) { fprintf(stderr, "no rrb\n"); return; } atom->cmd[CTX_RB3D_CNTL] &= ~(0xf << 10); if (rrb->cpp == 4) atom->cmd[CTX_RB3D_CNTL] |= RADEON_COLOR_FORMAT_ARGB8888; else switch (rrb->base.Format) { case MESA_FORMAT_RGB565: atom->cmd[CTX_RB3D_CNTL] |= RADEON_COLOR_FORMAT_RGB565; break; case MESA_FORMAT_ARGB4444: atom->cmd[CTX_RB3D_CNTL] |= RADEON_COLOR_FORMAT_ARGB4444; break; case MESA_FORMAT_ARGB1555: atom->cmd[CTX_RB3D_CNTL] |= RADEON_COLOR_FORMAT_ARGB1555; break; default: _mesa_problem(ctx, "unexpected format in ctx_emit_cs()"); } cbpitch = (rrb->pitch / rrb->cpp); if (rrb->bo->flags & RADEON_BO_FLAGS_MACRO_TILE) cbpitch |= R200_COLOR_TILE_ENABLE; drb = radeon_get_depthbuffer(&r100->radeon); if (drb) { zbpitch = (drb->pitch / drb->cpp); if (drb->cpp == 4) depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z; else depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z; atom->cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_DEPTH_FORMAT_MASK; atom->cmd[CTX_RB3D_ZSTENCILCNTL] |= depth_fmt; } BEGIN_BATCH_NO_AUTOSTATE(dwords); /* In the CS case we need to split this up */ OUT_BATCH(CP_PACKET0(packet[0].start, 3)); OUT_BATCH_TABLE((atom->cmd + 1), 4); if (drb) { OUT_BATCH(CP_PACKET0(RADEON_RB3D_DEPTHOFFSET, 0)); OUT_BATCH_RELOC(0, drb->bo, 0, 0, RADEON_GEM_DOMAIN_VRAM, 0); OUT_BATCH(CP_PACKET0(RADEON_RB3D_DEPTHPITCH, 0)); OUT_BATCH(zbpitch); } OUT_BATCH(CP_PACKET0(RADEON_RB3D_ZSTENCILCNTL, 0)); OUT_BATCH(atom->cmd[CTX_RB3D_ZSTENCILCNTL]); OUT_BATCH(CP_PACKET0(RADEON_PP_CNTL, 1)); OUT_BATCH(atom->cmd[CTX_PP_CNTL]); OUT_BATCH(atom->cmd[CTX_RB3D_CNTL]); if (rrb) { OUT_BATCH(CP_PACKET0(RADEON_RB3D_COLOROFFSET, 0)); OUT_BATCH_RELOC(0, rrb->bo, 0, 0, RADEON_GEM_DOMAIN_VRAM, 0); OUT_BATCH(CP_PACKET0(RADEON_RB3D_COLORPITCH, 0)); OUT_BATCH_RELOC(cbpitch, rrb->bo, cbpitch, 0, RADEON_GEM_DOMAIN_VRAM, 0); } // if (atom->cmd_size == CTX_STATE_SIZE_NEWDRM) { // OUT_BATCH_TABLE((atom->cmd + 14), 4); // } END_BATCH(); BEGIN_BATCH_NO_AUTOSTATE(4); OUT_BATCH(CP_PACKET0(RADEON_RE_TOP_LEFT, 0)); OUT_BATCH(0); OUT_BATCH(CP_PACKET0(RADEON_RE_WIDTH_HEIGHT, 0)); if (rrb) { OUT_BATCH(((rrb->base.Width - 1) << RADEON_RE_WIDTH_SHIFT) | ((rrb->base.Height - 1) << RADEON_RE_HEIGHT_SHIFT)); } else { OUT_BATCH(0); } END_BATCH(); }
static const struct gl_texture_format * mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat, GLenum format, GLenum type ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); const GLboolean do32bpt = mmesa->default32BitTextures; switch ( internalFormat ) { case 4: case GL_RGBA: case GL_COMPRESSED_RGBA: if ( format == GL_BGRA ) { if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) { return &_mesa_texformat_argb8888; } else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { return &_mesa_texformat_argb4444; } else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { return &_mesa_texformat_argb1555; } } return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case 3: case GL_RGB: case GL_COMPRESSED_RGB: if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { return &_mesa_texformat_rgb565; } return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case GL_RGBA4: case GL_RGBA2: return &_mesa_texformat_argb4444; case GL_RGB5_A1: return &_mesa_texformat_argb1555; case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; case GL_RGB5: case GL_RGB4: case GL_R3_G3_B2: return &_mesa_texformat_rgb565; case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8: case GL_ALPHA12: case GL_ALPHA16: case GL_COMPRESSED_ALPHA: /* FIXME: This will report incorrect component sizes... */ return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444; case 1: case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8: case GL_LUMINANCE12: case GL_LUMINANCE16: case GL_COMPRESSED_LUMINANCE: /* FIXME: This will report incorrect component sizes... */ return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_rgb565; case 2: case GL_LUMINANCE_ALPHA: case GL_LUMINANCE4_ALPHA4: case GL_LUMINANCE6_ALPHA2: case GL_LUMINANCE8_ALPHA8: case GL_LUMINANCE12_ALPHA4: case GL_LUMINANCE12_ALPHA12: case GL_LUMINANCE16_ALPHA16: case GL_COMPRESSED_LUMINANCE_ALPHA: /* FIXME: This will report incorrect component sizes... */ return MGA_IS_G400(mmesa) ? &_mesa_texformat_al88 : &_mesa_texformat_argb4444; case GL_INTENSITY: case GL_INTENSITY4: case GL_INTENSITY8: case GL_INTENSITY12: case GL_INTENSITY16: case GL_COMPRESSED_INTENSITY: /* FIXME: This will report incorrect component sizes... */ return MGA_IS_G400(mmesa) ? &_mesa_texformat_i8 : &_mesa_texformat_argb4444; case GL_YCBCR_MESA: if (MGA_IS_G400(mmesa) && (type == GL_UNSIGNED_SHORT_8_8_APPLE || type == GL_UNSIGNED_BYTE)) return &_mesa_texformat_ycbcr; else return &_mesa_texformat_ycbcr_rev; case GL_COLOR_INDEX: case GL_COLOR_INDEX1_EXT: case GL_COLOR_INDEX2_EXT: case GL_COLOR_INDEX4_EXT: case GL_COLOR_INDEX8_EXT: case GL_COLOR_INDEX12_EXT: case GL_COLOR_INDEX16_EXT: return &_mesa_texformat_ci8; default: _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ ); return NULL; } return NULL; /* never get here */ }
/** * Examine texture unit's combine/env state to update derived state. */ static void update_tex_combine(struct gl_context *ctx, struct gl_texture_unit *texUnit, struct gl_fixedfunc_texture_unit *fftexUnit) { struct gl_tex_env_combine_state *combine; /* No combiners will apply to this. */ if (texUnit->_Current->Target == GL_TEXTURE_BUFFER) return; /* Set the texUnit->_CurrentCombine field to point to the user's combiner * state, or the combiner state which is derived from traditional texenv * mode. */ if (fftexUnit->EnvMode == GL_COMBINE || fftexUnit->EnvMode == GL_COMBINE4_NV) { fftexUnit->_CurrentCombine = & fftexUnit->Combine; } else { const struct gl_texture_object *texObj = texUnit->_Current; GLenum format = texObj->Image[0][texObj->BaseLevel]->_BaseFormat; if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT) { format = texObj->DepthMode; } calculate_derived_texenv(&fftexUnit->_EnvMode, fftexUnit->EnvMode, format); fftexUnit->_CurrentCombine = & fftexUnit->_EnvMode; } combine = fftexUnit->_CurrentCombine; /* Determine number of source RGB terms in the combiner function */ switch (combine->ModeRGB) { case GL_REPLACE: combine->_NumArgsRGB = 1; break; case GL_ADD: case GL_ADD_SIGNED: if (fftexUnit->EnvMode == GL_COMBINE4_NV) combine->_NumArgsRGB = 4; else combine->_NumArgsRGB = 2; break; case GL_MODULATE: case GL_SUBTRACT: case GL_DOT3_RGB: case GL_DOT3_RGBA: case GL_DOT3_RGB_EXT: case GL_DOT3_RGBA_EXT: combine->_NumArgsRGB = 2; break; case GL_INTERPOLATE: case GL_MODULATE_ADD_ATI: case GL_MODULATE_SIGNED_ADD_ATI: case GL_MODULATE_SUBTRACT_ATI: combine->_NumArgsRGB = 3; break; default: combine->_NumArgsRGB = 0; _mesa_problem(ctx, "invalid RGB combine mode in update_texture_state"); return; } /* Determine number of source Alpha terms in the combiner function */ switch (combine->ModeA) { case GL_REPLACE: combine->_NumArgsA = 1; break; case GL_ADD: case GL_ADD_SIGNED: if (fftexUnit->EnvMode == GL_COMBINE4_NV) combine->_NumArgsA = 4; else combine->_NumArgsA = 2; break; case GL_MODULATE: case GL_SUBTRACT: combine->_NumArgsA = 2; break; case GL_INTERPOLATE: case GL_MODULATE_ADD_ATI: case GL_MODULATE_SIGNED_ADD_ATI: case GL_MODULATE_SUBTRACT_ATI: combine->_NumArgsA = 3; break; default: combine->_NumArgsA = 0; _mesa_problem(ctx, "invalid Alpha combine mode in update_texture_state"); break; } pack_tex_combine(fftexUnit); }
/** * As above, but color index mode. */ void _swrast_fog_ci_span( const GLcontext *ctx, struct sw_span *span ) { const SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLuint haveW = (span->interpMask & SPAN_W); const GLuint fogIndex = (GLuint) ctx->Fog.Index; GLuint *index = span->array->index; ASSERT(swrast->_FogEnabled); ASSERT(span->arrayMask & SPAN_INDEX); ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG); /* we need to compute fog blend factors */ if (swrast->_PreferPixelFog) { /* The span's fog values are fog coordinates, now compute blend factors * and blend the fragment colors with the fog color. */ switch (ctx->Fog.Mode) { case GL_LINEAR: { const GLfloat fogEnd = ctx->Fog.End; const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End) ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start); const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f = (fogEnd - fogCoord / w) * fogScale; f = CLAMP(f, 0.0F, 1.0F); index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex); fogCoord += fogStep; w += wStep; } } break; case GL_EXP: { const GLfloat density = -ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f = (GLfloat) exp(density * fogCoord / w); f = CLAMP(f, 0.0F, 1.0F); index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex); fogCoord += fogStep; w += wStep; } } break; case GL_EXP2: { const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { const GLfloat coord = fogCoord / w; GLfloat tmp = negDensitySquared * coord * coord; GLfloat f; #if defined(__alpha__) || defined(__alpha) /* XXX this underflow check may be needed for other systems*/ if (tmp < FLT_MIN_10_EXP) tmp = FLT_MIN_10_EXP; #endif f = (GLfloat) exp(tmp); f = CLAMP(f, 0.0F, 1.0F); index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex); fogCoord += fogStep; w += wStep; } } break; default: _mesa_problem(ctx, "Bad fog mode in _swrast_fog_ci_span"); return; } } else if (span->arrayMask & SPAN_FOG) { /* The span's fog array values are blend factors. * They were previously computed per-vertex. */ GLuint i; for (i = 0; i < span->end; i++) { const GLfloat f = span->array->fog[i]; index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex); } } else { /* The span's fog start/step values are blend factors. * They were previously computed per-vertex. */ const GLfloat fogStep = span->fogStep; GLfloat fog = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; ASSERT(span->interpMask & SPAN_FOG); for (i = 0; i < span->end; i++) { const GLfloat f = fog / w; index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex); fog += fogStep; w += wStep; } } }
/** * Apply stencil test to an array of stencil values (before depth buffering). * Input: face - 0 or 1 for front or back-face polygons * n - number of pixels in the array * stencil - array of [n] stencil values * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel * Output: mask - pixels which fail the stencil test will have their * mask flag set to 0. * stencil - updated stencil values (where the test passed) * Return: GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. */ static GLboolean do_stencil_test( GLcontext *ctx, GLuint face, GLuint n, GLstencil stencil[], GLubyte mask[] ) { GLubyte fail[MAX_WIDTH]; GLboolean allfail = GL_FALSE; GLuint i; GLstencil r, s; const GLuint valueMask = ctx->Stencil.ValueMask[face]; ASSERT(n <= MAX_WIDTH); /* * Perform stencil test. The results of this operation are stored * in the fail[] array: * IF fail[i] is non-zero THEN * the stencil fail operator is to be applied * ELSE * the stencil fail operator is not to be applied * ENDIF */ switch (ctx->Stencil.Function[face]) { case GL_NEVER: /* never pass; always fail */ for (i=0;i<n;i++) { if (mask[i]) { mask[i] = 0; fail[i] = 1; } else { fail[i] = 0; } } allfail = GL_TRUE; break; case GL_LESS: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r < s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_LEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r <= s) { /* pass */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GREATER: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r > s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r >= s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_EQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r == s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_NOTEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { s = (GLstencil) (stencil[i] & valueMask); if (r != s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_ALWAYS: /* always pass */ for (i=0;i<n;i++) { fail[i] = 0; } break; default: _mesa_problem(ctx, "Bad stencil func in gl_stencil_span"); return 0; } if (ctx->Stencil.FailFunc[face] != GL_KEEP) { apply_stencil_op( ctx, ctx->Stencil.FailFunc[face], face, n, stencil, fail ); } return !allfail; }
/** * Apply fog to a span of RGBA pixels. * The fog value are either in the span->array->fog array or interpolated from * the fog/fogStep values. * They fog values are either fog coordinates (Z) or fog blend factors. * _PreferPixelFog should be in sync with that state! */ void _swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span ) { const SWcontext *swrast = SWRAST_CONTEXT(ctx); const GLchan rFog = swrast->_FogColor[RCOMP]; const GLchan gFog = swrast->_FogColor[GCOMP]; const GLchan bFog = swrast->_FogColor[BCOMP]; const GLuint haveW = (span->interpMask & SPAN_W); GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba; ASSERT(swrast->_FogEnabled); ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG); ASSERT(span->arrayMask & SPAN_RGBA); /* NOTE: if haveW is true, that means the fog start/step values are * perspective-corrected and we have to divide each fog coord by W. */ /* we need to compute fog blend factors */ if (swrast->_PreferPixelFog) { /* The span's fog values are fog coordinates, now compute blend factors * and blend the fragment colors with the fog color. */ switch (swrast->_FogMode) { case GL_LINEAR: { const GLfloat fogEnd = ctx->Fog.End; const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End) ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start); const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f, oneMinusF; f = (fogEnd - fogCoord / w) * fogScale; f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; case GL_EXP: { const GLfloat density = -ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { GLfloat f, oneMinusF; f = (GLfloat) exp(density * fogCoord / w); f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; case GL_EXP2: { const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density; const GLfloat fogStep = span->fogStep; GLfloat fogCoord = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; for (i = 0; i < span->end; i++) { const GLfloat coord = fogCoord / w; GLfloat tmp = negDensitySquared * coord * coord; GLfloat f, oneMinusF; #if defined(__alpha__) || defined(__alpha) /* XXX this underflow check may be needed for other systems*/ if (tmp < FLT_MIN_10_EXP) tmp = FLT_MIN_10_EXP; #endif f = (GLfloat) exp(tmp); f = CLAMP(f, 0.0F, 1.0F); oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); fogCoord += fogStep; w += wStep; } } break; default: _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span"); return; } } else if (span->arrayMask & SPAN_FOG) { /* The span's fog array values are blend factors. * They were previously computed per-vertex. */ GLuint i; for (i = 0; i < span->end; i++) { const GLfloat f = span->array->fog[i]; const GLfloat oneMinusF = 1.0F - f; rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog); } } else { /* The span's fog start/step values are blend factors. * They were previously computed per-vertex. */ const GLfloat fogStep = span->fogStep; GLfloat fog = span->fog; const GLfloat wStep = haveW ? span->dwdx : 0.0F; GLfloat w = haveW ? span->w : 1.0F; GLuint i; ASSERT(span->interpMask & SPAN_FOG); for (i = 0; i < span->end; i++) { const GLfloat fact = fog / w; const GLfloat oneMinusF = 1.0F - fact; rgba[i][RCOMP] = (GLchan) (fact * rgba[i][RCOMP] + oneMinusF * rFog); rgba[i][GCOMP] = (GLchan) (fact * rgba[i][GCOMP] + oneMinusF * gFog); rgba[i][BCOMP] = (GLchan) (fact * rgba[i][BCOMP] + oneMinusF * bFog); fog += fogStep; w += wStep; } } }
/** * Apply stencil test to an array of pixels before depth buffering. * * \note Used for software stencil buffer only. * Input: n - number of pixels in the span * x, y - array of [n] pixels to stencil * mask - array [n] of flag: 0=skip the pixel, 1=stencil the pixel * Output: mask - pixels which fail the stencil test will have their * mask flag set to 0. * \return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed. */ static GLboolean stencil_test_pixels( GLcontext *ctx, GLuint face, GLuint n, const GLint x[], const GLint y[], GLubyte mask[] ) { GLubyte fail[MAX_WIDTH]; GLstencil r, s; GLuint i; GLboolean allfail = GL_FALSE; const GLuint valueMask = ctx->Stencil.ValueMask[face]; /* software stencil buffer only! */ ASSERT(ctx->DrawBuffer->UseSoftwareStencilBuffer); ASSERT(!SWRAST_CONTEXT(ctx)->Driver.ReadStencilSpan); ASSERT(!SWRAST_CONTEXT(ctx)->Driver.WriteStencilSpan); /* * Perform stencil test. The results of this operation are stored * in the fail[] array: * IF fail[i] is non-zero THEN * the stencil fail operator is to be applied * ELSE * the stencil fail operator is not to be applied * ENDIF */ switch (ctx->Stencil.Function[face]) { case GL_NEVER: /* always fail */ for (i=0;i<n;i++) { if (mask[i]) { mask[i] = 0; fail[i] = 1; } else { fail[i] = 0; } } allfail = GL_TRUE; break; case GL_LESS: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r < s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_LEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r <= s) { /* pass */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GREATER: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r > s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_GEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r >= s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_EQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r == s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_NOTEQUAL: r = (GLstencil) (ctx->Stencil.Ref[face] & valueMask); for (i=0;i<n;i++) { if (mask[i]) { GLstencil *sptr = STENCIL_ADDRESS(x[i],y[i]); s = (GLstencil) (*sptr & valueMask); if (r != s) { /* passed */ fail[i] = 0; } else { fail[i] = 1; mask[i] = 0; } } else { fail[i] = 0; } } break; case GL_ALWAYS: /* always pass */ for (i=0;i<n;i++) { fail[i] = 0; } break; default: _mesa_problem(ctx, "Bad stencil func in gl_stencil_pixels"); return 0; } if (ctx->Stencil.FailFunc[face] != GL_KEEP) { apply_stencil_op_to_pixels( ctx, n, x, y, ctx->Stencil.FailFunc[face], face, fail ); } return !allfail; }
static void setup_glsl_msaa_blit_shader(struct gl_context *ctx, struct blit_state *blit, const struct gl_framebuffer *drawFb, struct gl_renderbuffer *src_rb, GLenum target) { const char *vs_source; char *fs_source; void *mem_ctx; enum blit_msaa_shader shader_index; bool dst_is_msaa = false; GLenum src_datatype; const char *vec4_prefix; const char *sampler_array_suffix = ""; char *name; const char *texcoord_type = "vec2"; int samples; int shader_offset = 0; if (src_rb) { samples = MAX2(src_rb->NumSamples, 1); src_datatype = _mesa_get_format_datatype(src_rb->Format); } else { /* depth-or-color glCopyTexImage fallback path that passes a NULL rb and * doesn't handle integer. */ samples = 1; src_datatype = GL_UNSIGNED_NORMALIZED; } /* We expect only power of 2 samples in source multisample buffer. */ assert(samples > 0 && _mesa_is_pow_two(samples)); while (samples >> (shader_offset + 1)) { shader_offset++; } /* Update the assert if we plan to support more than 16X MSAA. */ assert(shader_offset >= 0 && shader_offset <= 4); if (drawFb->Visual.samples > 1) { /* If you're calling meta_BlitFramebuffer with the destination * multisampled, this is the only path that will work -- swrast and * CopyTexImage won't work on it either. */ assert(ctx->Extensions.ARB_sample_shading); dst_is_msaa = true; /* We need shader invocation per sample, not per pixel */ _mesa_set_enable(ctx, GL_MULTISAMPLE, GL_TRUE); _mesa_set_enable(ctx, GL_SAMPLE_SHADING, GL_TRUE); _mesa_MinSampleShading(1.0); } switch (target) { case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: if (src_rb && (src_rb->_BaseFormat == GL_DEPTH_COMPONENT || src_rb->_BaseFormat == GL_DEPTH_STENCIL)) { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY; else shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE; } else { if (dst_is_msaa) shader_index = BLIT_MSAA_SHADER_2D_MULTISAMPLE_COPY; else { shader_index = BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + shader_offset; } } if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { shader_index += (BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_RESOLVE - BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE); sampler_array_suffix = "Array"; texcoord_type = "vec3"; } break; default: _mesa_problem(ctx, "Unkown texture target %s\n", _mesa_enum_to_string(target)); shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE; } /* We rely on the enum being sorted this way. */ STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_INT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 5); STATIC_ASSERT(BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE_UINT == BLIT_1X_MSAA_SHADER_2D_MULTISAMPLE_RESOLVE + 10); if (src_datatype == GL_INT) { shader_index += 5; vec4_prefix = "i"; } else if (src_datatype == GL_UNSIGNED_INT) { shader_index += 10; vec4_prefix = "u"; } else { vec4_prefix = ""; } if (blit->msaa_shaders[shader_index]) { _mesa_UseProgram(blit->msaa_shaders[shader_index]); return; } mem_ctx = ralloc_context(NULL); if (shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_RESOLVE || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_DEPTH_COPY || shader_index == BLIT_MSAA_SHADER_2D_MULTISAMPLE_DEPTH_COPY) { char *sample_index; const char *arb_sample_shading_extension_string; if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_index = "gl_SampleID"; name = "depth MSAA copy"; } else { /* Don't need that extension, since we're drawing to a single-sampled * destination. */ arb_sample_shading_extension_string = ""; /* From the GL 4.3 spec: * * "If there is a multisample buffer (the value of SAMPLE_BUFFERS * is one), then values are obtained from the depth samples in * this buffer. It is recommended that the depth value of the * centermost sample be used, though implementations may choose * any function of the depth sample values at each pixel. * * We're slacking and instead of choosing centermost, we've got 0. */ sample_index = "0"; name = "depth MSAA resolve"; } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "uniform sampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out vec4 out_color;\n" "\n" "void main()\n" "{\n" " gl_FragDepth = texelFetch(texSampler, i%s(texCoords), %s).r;\n" "}\n", arb_sample_shading_extension_string, sampler_array_suffix, texcoord_type, texcoord_type, sample_index); } else { /* You can create 2D_MULTISAMPLE textures with 0 sample count (meaning 1 * sample). Yes, this is ridiculous. */ char *sample_resolve; const char *arb_sample_shading_extension_string; const char *merge_function; name = ralloc_asprintf(mem_ctx, "%svec4 MSAA %s", vec4_prefix, dst_is_msaa ? "copy" : "resolve"); if (dst_is_msaa) { arb_sample_shading_extension_string = "#extension GL_ARB_sample_shading : enable"; sample_resolve = ralloc_asprintf(mem_ctx, " out_color = texelFetch(texSampler, i%s(texCoords), gl_SampleID);", texcoord_type); merge_function = ""; } else { int i; int step; if (src_datatype == GL_INT || src_datatype == GL_UNSIGNED_INT) { merge_function = "gvec4 merge(gvec4 a, gvec4 b) { return (a >> gvec4(1)) + (b >> gvec4(1)) + (a & b & gvec4(1)); }\n"; } else { /* The divide will happen at the end for floats. */ merge_function = "vec4 merge(vec4 a, vec4 b) { return (a + b); }\n"; } arb_sample_shading_extension_string = ""; /* We're assuming power of two samples for this resolution procedure. * * To avoid losing any floating point precision if the samples all * happen to have the same value, we merge pairs of values at a time * (so the floating point exponent just gets increased), rather than * doing a naive sum and dividing. */ assert(_mesa_is_pow_two(samples)); /* Fetch each individual sample. */ sample_resolve = rzalloc_size(mem_ctx, 1); for (i = 0; i < samples; i++) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_1_%d = texelFetch(texSampler, i%s(texCoords), %d);\n", i, texcoord_type, i); } /* Now, merge each pair of samples, then merge each pair of those, * etc. */ for (step = 2; step <= samples; step *= 2) { for (i = 0; i < samples; i += step) { ralloc_asprintf_append(&sample_resolve, " gvec4 sample_%d_%d = merge(sample_%d_%d, sample_%d_%d);\n", step, i, step / 2, i, step / 2, i + step / 2); } } /* Scale the final result. */ if (src_datatype == GL_UNSIGNED_INT || src_datatype == GL_INT) { ralloc_asprintf_append(&sample_resolve, " out_color = sample_%d_0;\n", samples); } else { ralloc_asprintf_append(&sample_resolve, " gl_FragColor = sample_%d_0 / %f;\n", samples, (float)samples); } } vs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "in vec2 position;\n" "in %s textureCoords;\n" "out %s texCoords;\n" "void main()\n" "{\n" " texCoords = textureCoords;\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n", texcoord_type, texcoord_type); fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "%s\n" "#define gvec4 %svec4\n" "uniform %ssampler2DMS%s texSampler;\n" "in %s texCoords;\n" "out gvec4 out_color;\n" "\n" "%s" /* merge_function */ "void main()\n" "{\n" "%s\n" /* sample_resolve */ "}\n", arb_sample_shading_extension_string, vec4_prefix, vec4_prefix, sampler_array_suffix, texcoord_type, merge_function, sample_resolve); } _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name, &blit->msaa_shaders[shader_index]); ralloc_free(mem_ctx); }
static void texgen( GLcontext *ctx, struct texgen_stage_data *store, GLuint unit ) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLvector4f *in = VB->AttribPtr[VERT_ATTRIB_TEX0 + unit]; GLvector4f *out = &store->texcoord[unit]; const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; const GLvector4f *obj = VB->ObjPtr; const GLvector4f *eye = VB->EyePtr; const GLvector4f *normal = VB->AttribPtr[_TNL_ATTRIB_NORMAL]; const GLfloat *m = store->tmp_m; const GLuint count = VB->Count; GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data; GLfloat (*f)[3] = store->tmp_f; GLuint copy; if (texUnit->_GenFlags & TEXGEN_NEED_M) { build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye ); } else if (texUnit->_GenFlags & TEXGEN_NEED_F) { build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye ); } out->size = MAX2(in->size, store->TexgenSize[unit]); out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled; out->count = count; copy = (all_bits[in->size] & ~texUnit->TexGenEnabled); if (copy) _mesa_copy_tab[copy]( out, in ); if (texUnit->TexGenEnabled & S_BIT) { GLuint i; switch (texUnit->GenS.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( (GLfloat *)out->data, sizeof(out->data[0]), obj, texUnit->GenS.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data, sizeof(out->data[0]), eye, texUnit->GenS.EyePlane ); break; case GL_SPHERE_MAP: for (i = 0; i < count; i++) texcoord[i][0] = f[i][0] * m[i] + 0.5F; break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][0] = f[i][0]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { texcoord[i][0] = norm[0]; } break; } default: _mesa_problem(ctx, "Bad S texgen"); } } if (texUnit->TexGenEnabled & T_BIT) { GLuint i; switch (texUnit->GenT.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][1]), sizeof(out->data[0]), obj, texUnit->GenT.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][1]), sizeof(out->data[0]), eye, texUnit->GenT.EyePlane ); break; case GL_SPHERE_MAP: for (i = 0; i < count; i++) texcoord[i][1] = f[i][1] * m[i] + 0.5F; break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][1] = f[i][1]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) { texcoord[i][1] = norm[1]; } break; } default: _mesa_problem(ctx, "Bad T texgen"); } } if (texUnit->TexGenEnabled & R_BIT) { GLuint i; switch (texUnit->GenR.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][2]), sizeof(out->data[0]), obj, texUnit->GenR.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][2]), sizeof(out->data[0]), eye, texUnit->GenR.EyePlane ); break; case GL_REFLECTION_MAP_NV: for (i=0;i<count;i++) texcoord[i][2] = f[i][2]; break; case GL_NORMAL_MAP_NV: { const GLfloat *norm = normal->start; for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) { texcoord[i][2] = norm[2]; } break; } default: _mesa_problem(ctx, "Bad R texgen"); } } if (texUnit->TexGenEnabled & Q_BIT) { switch (texUnit->GenQ.Mode) { case GL_OBJECT_LINEAR: _mesa_dotprod_tab[obj->size]( &(out->data[0][3]), sizeof(out->data[0]), obj, texUnit->GenQ.ObjectPlane ); break; case GL_EYE_LINEAR: _mesa_dotprod_tab[eye->size]( &(out->data[0][3]), sizeof(out->data[0]), eye, texUnit->GenQ.EyePlane ); break; default: _mesa_problem(ctx, "Bad Q texgen"); } } }
static void setup_glsl_msaa_blit_scaled_shader(struct gl_context *ctx, struct blit_state *blit, struct gl_renderbuffer *src_rb, GLenum target, GLenum filter) { GLint loc_src_width, loc_src_height; int i, samples; int shader_offset = 0; void *mem_ctx = ralloc_context(NULL); char *fs_source; char *name, *sample_number; const uint8_t *sample_map; char *sample_map_str = rzalloc_size(mem_ctx, 1); char *sample_map_expr = rzalloc_size(mem_ctx, 1); char *texel_fetch_macro = rzalloc_size(mem_ctx, 1); const char *sampler_array_suffix = ""; float y_scale; enum blit_msaa_shader shader_index; assert(src_rb); samples = MAX2(src_rb->NumSamples, 1); y_scale = samples * 0.5; /* We expect only power of 2 samples in source multisample buffer. */ assert(samples > 0 && _mesa_is_pow_two(samples)); while (samples >> (shader_offset + 1)) { shader_offset++; } /* Update the assert if we plan to support more than 8X MSAA. */ assert(shader_offset > 0 && shader_offset < 4); assert(target == GL_TEXTURE_2D_MULTISAMPLE || target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); shader_index = BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_SCALED_RESOLVE + shader_offset - 1; if (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) { shader_index += BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_ARRAY_SCALED_RESOLVE - BLIT_2X_MSAA_SHADER_2D_MULTISAMPLE_SCALED_RESOLVE; sampler_array_suffix = "Array"; } if (blit->msaa_shaders[shader_index]) { _mesa_UseProgram(blit->msaa_shaders[shader_index]); /* Update the uniform values. */ loc_src_width = _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_width"); loc_src_height = _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_height"); _mesa_Uniform1f(loc_src_width, src_rb->Width); _mesa_Uniform1f(loc_src_height, src_rb->Height); return; } name = ralloc_asprintf(mem_ctx, "vec4 MSAA scaled resolve"); /* Below switch is used to setup the shader expression, which computes * sample index and map it to to a sample number on hardware. */ switch(samples) { case 2: sample_number = "sample_map[int(2 * fract(coord.x))]"; sample_map = ctx->Const.SampleMap2x; break; case 4: sample_number = "sample_map[int(2 * fract(coord.x) + 4 * fract(coord.y))]"; sample_map = ctx->Const.SampleMap4x; break; case 8: sample_number = "sample_map[int(2 * fract(coord.x) + 8 * fract(coord.y))]"; sample_map = ctx->Const.SampleMap8x; break; default: sample_number = NULL; sample_map = NULL; _mesa_problem(ctx, "Unsupported sample count %d\n", samples); unreachable("Unsupported sample count"); } /* Create sample map string. */ for (i = 0 ; i < samples - 1; i++) { ralloc_asprintf_append(&sample_map_str, "%d, ", sample_map[i]); } ralloc_asprintf_append(&sample_map_str, "%d", sample_map[samples - 1]); /* Create sample map expression using above string. */ ralloc_asprintf_append(&sample_map_expr, " const int sample_map[%d] = int[%d](%s);\n", samples, samples, sample_map_str); if (target == GL_TEXTURE_2D_MULTISAMPLE) { ralloc_asprintf_append(&texel_fetch_macro, "#define TEXEL_FETCH(coord) texelFetch(texSampler, ivec2(coord), %s);\n", sample_number); } else { ralloc_asprintf_append(&texel_fetch_macro, "#define TEXEL_FETCH(coord) texelFetch(texSampler, ivec3(coord, layer), %s);\n", sample_number); } static const char vs_source[] = "#version 130\n" "in vec2 position;\n" "in vec3 textureCoords;\n" "out vec2 texCoords;\n" "flat out int layer;\n" "void main()\n" "{\n" " texCoords = textureCoords.xy;\n" " layer = int(textureCoords.z);\n" " gl_Position = vec4(position, 0.0, 1.0);\n" "}\n" ; fs_source = ralloc_asprintf(mem_ctx, "#version 130\n" "#extension GL_ARB_texture_multisample : enable\n" "uniform sampler2DMS%s texSampler;\n" "uniform float src_width, src_height;\n" "in vec2 texCoords;\n" "flat in int layer;\n" "out vec4 out_color;\n" "\n" "void main()\n" "{\n" "%s" " vec2 interp;\n" " const vec2 scale = vec2(2.0f, %ff);\n" " const vec2 scale_inv = vec2(0.5f, %ff);\n" " const vec2 s_0_offset = vec2(0.25f, %ff);\n" " vec2 s_0_coord, s_1_coord, s_2_coord, s_3_coord;\n" " vec4 s_0_color, s_1_color, s_2_color, s_3_color;\n" " vec4 x_0_color, x_1_color;\n" " vec2 tex_coord = texCoords - s_0_offset;\n" "\n" " tex_coord *= scale;\n" " clamp(tex_coord.x, 0.0f, scale.x * src_width - 1.0f);\n" " clamp(tex_coord.y, 0.0f, scale.y * src_height - 1.0f);\n" " interp = fract(tex_coord);\n" " tex_coord = ivec2(tex_coord) * scale_inv;\n" "\n" " /* Compute the sample coordinates used for filtering. */\n" " s_0_coord = tex_coord;\n" " s_1_coord = tex_coord + vec2(scale_inv.x, 0.0f);\n" " s_2_coord = tex_coord + vec2(0.0f, scale_inv.y);\n" " s_3_coord = tex_coord + vec2(scale_inv.x, scale_inv.y);\n" "\n" " /* Fetch sample color values. */\n" "%s" " s_0_color = TEXEL_FETCH(s_0_coord)\n" " s_1_color = TEXEL_FETCH(s_1_coord)\n" " s_2_color = TEXEL_FETCH(s_2_coord)\n" " s_3_color = TEXEL_FETCH(s_3_coord)\n" "#undef TEXEL_FETCH\n" "\n" " /* Do bilinear filtering on sample colors. */\n" " x_0_color = mix(s_0_color, s_1_color, interp.x);\n" " x_1_color = mix(s_2_color, s_3_color, interp.x);\n" " out_color = mix(x_0_color, x_1_color, interp.y);\n" "}\n", sampler_array_suffix, sample_map_expr, y_scale, 1.0f / y_scale, 1.0f / samples, texel_fetch_macro); _mesa_meta_compile_and_link_program(ctx, vs_source, fs_source, name, &blit->msaa_shaders[shader_index]); loc_src_width = _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_width"); loc_src_height = _mesa_GetUniformLocation(blit->msaa_shaders[shader_index], "src_height"); _mesa_Uniform1f(loc_src_width, src_rb->Width); _mesa_Uniform1f(loc_src_height, src_rb->Height); ralloc_free(mem_ctx); }
/** * Called via glRenderbufferStorageEXT() to set the format and allocate * storage for a user-created renderbuffer. */ static GLboolean intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct intel_context *intel = intel_context(ctx); struct intel_renderbuffer *irb = intel_renderbuffer(rb); int cpp; GLuint pitch; ASSERT(rb->Name != 0); switch (internalFormat) { case GL_R3_G3_B2: case GL_RGB4: case GL_RGB5: rb->Format = MESA_FORMAT_RGB565; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGB: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: rb->Format = MESA_FORMAT_XRGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1: case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: rb->Format = MESA_FORMAT_ARGB8888; rb->DataType = GL_UNSIGNED_BYTE; break; case GL_STENCIL_INDEX: case GL_STENCIL_INDEX1_EXT: case GL_STENCIL_INDEX4_EXT: case GL_STENCIL_INDEX8_EXT: case GL_STENCIL_INDEX16_EXT: /* alloc a depth+stencil buffer */ rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_COMPONENT16: rb->Format = MESA_FORMAT_Z16; rb->DataType = GL_UNSIGNED_SHORT; break; case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; case GL_DEPTH_STENCIL_EXT: case GL_DEPTH24_STENCIL8_EXT: rb->Format = MESA_FORMAT_S8_Z24; rb->DataType = GL_UNSIGNED_INT_24_8_EXT; break; default: _mesa_problem(ctx, "Unexpected format in intel_alloc_renderbuffer_storage"); return GL_FALSE; } rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); cpp = _mesa_get_format_bytes(rb->Format); intelFlush(ctx); /* free old region */ if (irb->region) { intel_region_release(&irb->region); } /* allocate new memory region/renderbuffer */ /* Choose a pitch to match hardware requirements: */ pitch = ((cpp * width + 63) & ~63) / cpp; /* alloc hardware renderbuffer */ DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, height, pitch); irb->region = intel_region_alloc(intel, I915_TILING_NONE, cpp, width, height, pitch, GL_TRUE); if (!irb->region) return GL_FALSE; /* out of memory? */ ASSERT(irb->region->buffer); rb->Width = width; rb->Height = height; return GL_TRUE; }
/** * Disable the named extension. * XXX is this really needed??? */ void _mesa_disable_extension( struct gl_context *ctx, const char *name ) { if (!set_extension(ctx, name, GL_FALSE)) _mesa_problem(ctx, "Trying to disable unknown extension: %s", name); }