/** * Replace data in a subrange of buffer object. If the data range * specified by size + offset extends beyond the end of the buffer or * if data is NULL, no copy is performed. * Called via glBufferSubDataARB(). */ static void st_bufferobj_subdata(struct gl_context *ctx, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data, struct gl_buffer_object *obj) { struct st_buffer_object *st_obj = st_buffer_object(obj); /* we may be called from VBO code, so double-check params here */ ASSERT(offset >= 0); ASSERT(size >= 0); ASSERT(offset + size <= obj->Size); if (!size) return; /* * According to ARB_vertex_buffer_object specification, if data is null, * then the contents of the buffer object's data store is undefined. We just * ignore, and leave it unchanged. */ if (!data) return; if (!st_obj->buffer) { /* we probably ran out of memory during buffer allocation */ return; } /* Now that transfers are per-context, we don't have to figure out * flushing here. Usually drivers won't need to flush in this case * even if the buffer is currently referenced by hardware - they * just queue the upload as dma rather than mapping the underlying * buffer directly. */ pipe_buffer_write(st_context(ctx)->pipe, st_obj->buffer, offset, size, data); }
static GLboolean st_renderbuffer_alloc_sw_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct st_context *st = st_context(ctx); struct st_renderbuffer *strb = st_renderbuffer(rb); enum pipe_format format; size_t size; free(strb->data); strb->data = NULL; if (internalFormat == GL_RGBA16_SNORM) { /* Special case for software accum buffers. Otherwise, if the * call to st_choose_renderbuffer_format() fails (because the * driver doesn't support signed 16-bit/channel colors) we'd * just return without allocating the software accum buffer. */ format = PIPE_FORMAT_R16G16B16A16_SNORM; } else { format = st_choose_renderbuffer_format(st, internalFormat, 0); /* Not setting gl_renderbuffer::Format here will cause * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. */ if (format == PIPE_FORMAT_NONE) { return GL_TRUE; } } strb->Base.Format = st_pipe_format_to_mesa_format(format); size = _mesa_format_image_size(strb->Base.Format, width, height, 1); strb->data = malloc(size); return strb->data != NULL; }
/** * Called via glMapBufferRange(). */ static void * st_bufferobj_map_range(GLcontext *ctx, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, struct gl_buffer_object *obj) { struct pipe_context *pipe = st_context(ctx)->pipe; struct st_buffer_object *st_obj = st_buffer_object(obj); GLuint flags = 0; char *map; if (access & GL_MAP_WRITE_BIT) flags |= PIPE_BUFFER_USAGE_CPU_WRITE; if (access & GL_MAP_READ_BIT) flags |= PIPE_BUFFER_USAGE_CPU_READ; if (access & GL_MAP_FLUSH_EXPLICIT_BIT) flags |= PIPE_BUFFER_USAGE_FLUSH_EXPLICIT; /* ... other flags ... */ if (access & MESA_MAP_NOWAIT_BIT) flags |= PIPE_BUFFER_USAGE_DONTBLOCK; assert(offset >= 0); assert(length >= 0); assert(offset < obj->Size); assert(offset + length <= obj->Size); map = obj->Pointer = pipe_buffer_map_range(pipe->screen, st_obj->buffer, offset, length, flags); if(obj->Pointer) { obj->Offset = offset; obj->Length = length; map += offset; } return map; }
static void st_bufferobj_flush_mapped_range(struct gl_context *ctx, GLintptr offset, GLsizeiptr length, struct gl_buffer_object *obj, gl_map_buffer_index index) { struct pipe_context *pipe = st_context(ctx)->pipe; struct st_buffer_object *st_obj = st_buffer_object(obj); /* Subrange is relative to mapped range */ assert(offset >= 0); assert(length >= 0); assert(offset + length <= obj->Mappings[index].Length); assert(obj->Mappings[index].Pointer); if (!length) return; pipe_buffer_flush_mapped_range(pipe, st_obj->transfer[index], obj->Mappings[index].Offset + offset, length); }
/** * Called via ctx->Driver.UpdateState() */ void st_invalidate_state(struct gl_context * ctx, GLuint new_state) { struct st_context *st = st_context(ctx); /* Replace _NEW_FRAG_CLAMP with ST_NEW_FRAGMENT_PROGRAM for the fallback. */ if (st->clamp_frag_color_in_shader && (new_state & _NEW_FRAG_CLAMP)) { new_state &= ~_NEW_FRAG_CLAMP; st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; } /* Update the vertex shader if ctx->Light._ClampVertexColor was changed. */ if (st->clamp_vert_color_in_shader && (new_state & _NEW_LIGHT)) { st->dirty.st |= ST_NEW_VERTEX_PROGRAM; } st->dirty.mesa |= new_state; st->dirty.st |= ST_NEW_MESA; /* This is the only core Mesa module we depend upon. * No longer use swrast, swsetup, tnl. */ _vbo_InvalidateState(ctx, new_state); }
static void st_egl_image_target_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLeglImageOES image_handle) { struct st_context *st = st_context(ctx); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_surface *ps; ps = st_manager_get_egl_image_surface(st, (void *) image_handle); if (ps) { strb->Base.Width = ps->width; strb->Base.Height = ps->height; strb->Base.Format = st_pipe_format_to_mesa_format(ps->format); strb->Base._BaseFormat = st_pipe_format_to_base_format(ps->format); strb->Base.InternalFormat = strb->Base._BaseFormat; pipe_surface_reference(&strb->surface, ps); pipe_resource_reference(&strb->texture, ps->texture); pipe_surface_reference(&ps, NULL); } }
/** * Called via glClearBufferSubData(). */ static void st_clear_buffer_subdata(struct gl_context *ctx, GLintptr offset, GLsizeiptr size, const GLvoid *clearValue, GLsizeiptr clearValueSize, struct gl_buffer_object *bufObj) { struct pipe_context *pipe = st_context(ctx)->pipe; struct st_buffer_object *buf = st_buffer_object(bufObj); static const char zeros[16] = {0}; if (!pipe->clear_buffer) { _mesa_buffer_clear_subdata(ctx, offset, size, clearValue, clearValueSize, bufObj); return; } if (!clearValue) clearValue = zeros; pipe->clear_buffer(pipe, buf->buffer, offset, size, clearValue, clearValueSize); }
/** * Called via glCopyBufferSubData(). */ static void st_copy_buffer_subdata(struct gl_context *ctx, struct gl_buffer_object *src, struct gl_buffer_object *dst, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size) { struct pipe_context *pipe = st_context(ctx)->pipe; struct st_buffer_object *srcObj = st_buffer_object(src); struct st_buffer_object *dstObj = st_buffer_object(dst); struct pipe_box box; if (!size) return; /* buffer should not already be mapped */ assert(!src->Pointer); assert(!dst->Pointer); u_box_1d(readOffset, size, &box); pipe->resource_copy_region(pipe, dstObj->buffer, 0, writeOffset, 0, 0, srcObj->buffer, 0, &box); }
/** * Called via glGetBufferSubDataARB(). */ static void st_bufferobj_get_subdata(struct gl_context *ctx, GLintptrARB offset, GLsizeiptrARB size, GLvoid * data, struct gl_buffer_object *obj) { struct st_buffer_object *st_obj = st_buffer_object(obj); /* we may be called from VBO code, so double-check params here */ ASSERT(offset >= 0); ASSERT(size >= 0); ASSERT(offset + size <= obj->Size); if (!size) return; if (!st_obj->buffer) { /* we probably ran out of memory during buffer allocation */ return; } pipe_buffer_read(st_context(ctx)->pipe, st_obj->buffer, offset, size, data); }
static const GLubyte * st_get_string(struct gl_context * ctx, GLenum name) { struct st_context *st = st_context(ctx); struct pipe_screen *screen = st->pipe->screen; switch (name) { case GL_VENDOR: { const char *vendor = screen->get_vendor( screen ); util_snprintf(st->vendor, sizeof(st->vendor), "%s", vendor); return (GLubyte *) st->vendor; } case GL_RENDERER: util_snprintf(st->renderer, sizeof(st->renderer), "Gallium %s on %s", ST_VERSION_STRING, screen->get_name( screen )); return (GLubyte *) st->renderer; default: return NULL; } }
/** * Print current state. May be called from inside gdb to see currently * bound vertex/fragment shaders and associated constants. */ void st_print_current(void) { GET_CURRENT_CONTEXT(ctx); struct st_context *st = st_context(ctx); #if 0 int i; printf("Vertex Transform Inputs:\n"); for (i = 0; i < st->vp->state.num_inputs; i++) { printf(" Slot %d: VERT_ATTRIB_%d\n", i, st->vp->index_to_input[i]); } #endif if (st->vp->variants) tgsi_dump( st->vp->variants[0].tgsi.tokens, 0 ); if (st->vp->Base.Base.Parameters) _mesa_print_parameter_list(st->vp->Base.Base.Parameters); tgsi_dump( st->fp->variants[0].tgsi.tokens, 0 ); if (st->fp->Base.Base.Parameters) _mesa_print_parameter_list(st->fp->Base.Base.Parameters); }
/** * Called by VBO to draw arrays when in selection or feedback mode and * to implement glRasterPos. * This is very much like the normal draw_vbo() function above. * Look at code refactoring some day. */ void st_feedback_draw_vbo(struct gl_context *ctx, const struct gl_client_array **arrays, const struct _mesa_prim *prims, GLuint nr_prims, const struct _mesa_index_buffer *ib, GLboolean index_bounds_valid, GLuint min_index, GLuint max_index, struct gl_transform_feedback_object *tfb_vertcount) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct draw_context *draw = st->draw; const struct st_vertex_program *vp; const struct pipe_shader_state *vs; struct pipe_vertex_buffer vbuffers[PIPE_MAX_SHADER_INPUTS]; struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS]; struct pipe_index_buffer ibuffer; struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS]; struct pipe_transfer *ib_transfer = NULL; GLuint attr, i; const GLubyte *low_addr = NULL; const void *mapped_indices = NULL; assert(draw); st_validate_state(st); if (!index_bounds_valid) vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, nr_prims); /* must get these after state validation! */ vp = st->vp; vs = &st->vp_variant->tgsi; if (!st->vp_variant->draw_shader) { st->vp_variant->draw_shader = draw_create_vertex_shader(draw, vs); } /* * Set up the draw module's state. * * We'd like to do this less frequently, but the normal state-update * code sends state updates to the pipe, not to our private draw module. */ assert(draw); draw_set_viewport_state(draw, &st->state.viewport); draw_set_clip_state(draw, &st->state.clip); draw_set_rasterizer_state(draw, &st->state.rasterizer, NULL); draw_bind_vertex_shader(draw, st->vp_variant->draw_shader); set_feedback_vertex_format(ctx); /* Find the lowest address of the arrays we're drawing */ if (vp->num_inputs) { low_addr = arrays[vp->index_to_input[0]]->Ptr; for (attr = 1; attr < vp->num_inputs; attr++) { const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; low_addr = MIN2(low_addr, start); } } /* loop over TGSI shader inputs to determine vertex buffer * and attribute info */ for (attr = 0; attr < vp->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj; void *map; if (bufobj && bufobj->Name) { /* Attribute data is in a VBO. * Recall that for VBOs, the gl_client_array->Ptr field is * really an offset from the start of the VBO, not a pointer. */ struct st_buffer_object *stobj = st_buffer_object(bufobj); assert(stobj->buffer); vbuffers[attr].buffer = NULL; pipe_resource_reference(&vbuffers[attr].buffer, stobj->buffer); vbuffers[attr].buffer_offset = pointer_to_offset(low_addr); velements[attr].src_offset = arrays[mesaAttr]->Ptr - low_addr; } else { /* attribute data is in user-space memory, not a VBO */ uint bytes = (arrays[mesaAttr]->Size * _mesa_sizeof_type(arrays[mesaAttr]->Type) * (max_index + 1)); /* wrap user data */ vbuffers[attr].buffer = pipe_user_buffer_create(pipe->screen, (void *) arrays[mesaAttr]->Ptr, bytes, PIPE_BIND_VERTEX_BUFFER); vbuffers[attr].buffer_offset = 0; velements[attr].src_offset = 0; } /* common-case setup */ vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */ velements[attr].instance_divisor = 0; velements[attr].vertex_buffer_index = attr; velements[attr].src_format = st_pipe_vertex_format(arrays[mesaAttr]->Type, arrays[mesaAttr]->Size, arrays[mesaAttr]->Format, arrays[mesaAttr]->Normalized, arrays[mesaAttr]->Integer); assert(velements[attr].src_format); /* tell draw about this attribute */ #if 0 draw_set_vertex_buffer(draw, attr, &vbuffer[attr]); #endif /* map the attrib buffer */ map = pipe_buffer_map(pipe, vbuffers[attr].buffer, PIPE_TRANSFER_READ, &vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, map); } draw_set_vertex_buffers(draw, vp->num_inputs, vbuffers); draw_set_vertex_elements(draw, vp->num_inputs, velements); memset(&ibuffer, 0, sizeof(ibuffer)); if (ib) { struct gl_buffer_object *bufobj = ib->obj; ibuffer.index_size = vbo_sizeof_ib_type(ib->type); if (ibuffer.index_size == 0) goto out_unref_vertex; if (bufobj && bufobj->Name) { struct st_buffer_object *stobj = st_buffer_object(bufobj); pipe_resource_reference(&ibuffer.buffer, stobj->buffer); ibuffer.offset = pointer_to_offset(ib->ptr); mapped_indices = pipe_buffer_map(pipe, stobj->buffer, PIPE_TRANSFER_READ, &ib_transfer); } else { /* skip setting ibuffer.buffer as the draw module does not use it */ mapped_indices = ib->ptr; } draw_set_index_buffer(draw, &ibuffer); draw_set_mapped_index_buffer(draw, mapped_indices); } /* set the constant buffer */ draw_set_mapped_constant_buffer(st->draw, PIPE_SHADER_VERTEX, 0, st->state.constants[PIPE_SHADER_VERTEX].ptr, st->state.constants[PIPE_SHADER_VERTEX].size); /* draw here */ for (i = 0; i < nr_prims; i++) { draw_arrays(draw, prims[i].mode, prims[i].start, prims[i].count); } /* * unmap vertex/index buffers */ if (ib) { draw_set_mapped_index_buffer(draw, NULL); draw_set_index_buffer(draw, NULL); if (ib_transfer) pipe_buffer_unmap(pipe, ib_transfer); pipe_resource_reference(&ibuffer.buffer, NULL); } out_unref_vertex: for (attr = 0; attr < vp->num_inputs; attr++) { pipe_buffer_unmap(pipe, vb_transfer[attr]); draw_set_mapped_vertex_buffer(draw, attr, NULL); pipe_resource_reference(&vbuffers[attr].buffer, NULL); } draw_set_vertex_buffers(draw, 0, NULL); }
/** * gl_renderbuffer::AllocStorage() * This is called to allocate the original drawing surface, and * during window resize. */ static GLboolean st_renderbuffer_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = st->pipe->screen; struct st_renderbuffer *strb = st_renderbuffer(rb); enum pipe_format format = PIPE_FORMAT_NONE; struct pipe_surface surf_tmpl; struct pipe_resource templ; /* init renderbuffer fields */ strb->Base.Width = width; strb->Base.Height = height; strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); strb->defined = GL_FALSE; /* undefined contents now */ if (strb->software) { return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat, width, height); } /* Free the old surface and texture */ pipe_surface_reference( &strb->surface, NULL ); pipe_resource_reference( &strb->texture, NULL ); /* If an sRGB framebuffer is unsupported, sRGB formats behave like linear * formats. */ if (!ctx->Extensions.EXT_framebuffer_sRGB) { internalFormat = _mesa_get_linear_internalformat(internalFormat); } /* Handle multisample renderbuffers first. * * From ARB_framebuffer_object: * If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero. * Otherwise <samples> represents a request for a desired minimum * number of samples. Since different implementations may support * different sample counts for multisampled rendering, the actual * number of samples allocated for the renderbuffer image is * implementation dependent. However, the resulting value for * RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal * to <samples> and no more than the next larger sample count supported * by the implementation. * * So let's find the supported number of samples closest to NumSamples. * (NumSamples == 1) is treated the same as (NumSamples == 0). */ if (rb->NumSamples > 1) { unsigned i; for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) { format = st_choose_renderbuffer_format(st, internalFormat, i); if (format != PIPE_FORMAT_NONE) { rb->NumSamples = i; break; } } } else { format = st_choose_renderbuffer_format(st, internalFormat, 0); } /* Not setting gl_renderbuffer::Format here will cause * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called. */ if (format == PIPE_FORMAT_NONE) { return GL_TRUE; } strb->Base.Format = st_pipe_format_to_mesa_format(format); if (width == 0 || height == 0) { /* if size is zero, nothing to allocate */ return GL_TRUE; } /* Setup new texture template. */ memset(&templ, 0, sizeof(templ)); templ.target = st->internal_target; templ.format = format; templ.width0 = width; templ.height0 = height; templ.depth0 = 1; templ.array_size = 1; templ.nr_samples = rb->NumSamples; if (util_format_is_depth_or_stencil(format)) { templ.bind = PIPE_BIND_DEPTH_STENCIL; } else if (strb->Base.Name != 0) { /* this is a user-created renderbuffer */ templ.bind = PIPE_BIND_RENDER_TARGET; } else { /* this is a window-system buffer */ templ.bind = (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET); } strb->texture = screen->resource_create(screen, &templ); if (!strb->texture) return FALSE; u_surface_default_template(&surf_tmpl, strb->texture); strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl); if (strb->surface) { assert(strb->surface->texture); assert(strb->surface->format); assert(strb->surface->width == width); assert(strb->surface->height == height); } return strb->surface != NULL; }
/** * Translate a Mesa vertex shader into a TGSI shader. * \param outputMapping to map vertex program output registers (VARYING_SLOT_x) * to TGSI output slots * \param tokensOut destination for TGSI tokens * \return pointer to cached pipe_shader object. */ void st_prepare_vertex_program(struct gl_context *ctx, struct st_vertex_program *stvp) { struct st_context *st = st_context(ctx); GLuint attr; stvp->num_inputs = 0; stvp->num_outputs = 0; if (stvp->Base.IsPositionInvariant) _mesa_insert_mvp_code(ctx, &stvp->Base); /* * Determine number of inputs, the mappings between VERT_ATTRIB_x * and TGSI generic input indexes, plus input attrib semantic info. */ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) { if ((stvp->Base.Base.InputsRead & BITFIELD64_BIT(attr)) != 0) { stvp->input_to_index[attr] = stvp->num_inputs; stvp->index_to_input[stvp->num_inputs] = attr; stvp->num_inputs++; if ((stvp->Base.Base.DoubleInputsRead & BITFIELD64_BIT(attr)) != 0) { /* add placeholder for second part of a double attribute */ stvp->index_to_input[stvp->num_inputs] = ST_DOUBLE_ATTRIB_PLACEHOLDER; stvp->num_inputs++; } } } /* bit of a hack, presetup potentially unused edgeflag input */ stvp->input_to_index[VERT_ATTRIB_EDGEFLAG] = stvp->num_inputs; stvp->index_to_input[stvp->num_inputs] = VERT_ATTRIB_EDGEFLAG; /* Compute mapping of vertex program outputs to slots. */ for (attr = 0; attr < VARYING_SLOT_MAX; attr++) { if ((stvp->Base.Base.OutputsWritten & BITFIELD64_BIT(attr)) == 0) { stvp->result_to_output[attr] = ~0; } else { unsigned slot = stvp->num_outputs++; stvp->result_to_output[attr] = slot; switch (attr) { case VARYING_SLOT_POS: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_POSITION; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_COL0: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_COL1: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_COLOR; stvp->output_semantic_index[slot] = 1; break; case VARYING_SLOT_BFC0: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_BFC1: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_BCOLOR; stvp->output_semantic_index[slot] = 1; break; case VARYING_SLOT_FOGC: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_FOG; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_PSIZ: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_PSIZE; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_CLIP_DIST0: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_CLIP_DIST1: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPDIST; stvp->output_semantic_index[slot] = 1; break; case VARYING_SLOT_EDGE: assert(0); break; case VARYING_SLOT_CLIP_VERTEX: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_CLIPVERTEX; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_LAYER: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_LAYER; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_VIEWPORT: stvp->output_semantic_name[slot] = TGSI_SEMANTIC_VIEWPORT_INDEX; stvp->output_semantic_index[slot] = 0; break; case VARYING_SLOT_TEX0: case VARYING_SLOT_TEX1: case VARYING_SLOT_TEX2: case VARYING_SLOT_TEX3: case VARYING_SLOT_TEX4: case VARYING_SLOT_TEX5: case VARYING_SLOT_TEX6: case VARYING_SLOT_TEX7: if (st->needs_texcoord_semantic) { stvp->output_semantic_name[slot] = TGSI_SEMANTIC_TEXCOORD; stvp->output_semantic_index[slot] = attr - VARYING_SLOT_TEX0; break; } /* fall through */ case VARYING_SLOT_VAR0: default: assert(attr < VARYING_SLOT_MAX); stvp->output_semantic_name[slot] = TGSI_SEMANTIC_GENERIC; stvp->output_semantic_index[slot] = st_get_generic_varying_index(st, attr); break; } } } /* similar hack to above, presetup potentially unused edgeflag output */ stvp->result_to_output[VARYING_SLOT_EDGE] = stvp->num_outputs; stvp->output_semantic_name[stvp->num_outputs] = TGSI_SEMANTIC_EDGEFLAG; stvp->output_semantic_index[stvp->num_outputs] = 0; }
/** * Called by ctx->Driver.RenderTexture */ static void st_render_texture(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_renderbuffer *strb; struct gl_renderbuffer *rb; struct pipe_resource *pt; struct st_texture_object *stObj; const struct gl_texture_image *texImage; struct pipe_surface surf_tmpl; if (!st_finalize_texture(ctx, pipe, att->Texture)) return; pt = st_get_texobj_resource(att->Texture); assert(pt); /* get pointer to texture image we're rendeing to */ texImage = _mesa_get_attachment_teximage(att); /* create new renderbuffer which wraps the texture image. * Use the texture's name as the renderbuffer's name so that we have * something that's non-zero (to determine vertical orientation) and * possibly helpful for debugging. */ rb = st_new_renderbuffer(ctx, att->Texture->Name); if (!rb) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()"); return; } _mesa_reference_renderbuffer(&att->Renderbuffer, rb); assert(rb->RefCount == 1); rb->AllocStorage = NULL; /* should not get called */ strb = st_renderbuffer(rb); assert(strb->Base.RefCount > 0); /* get the texture for the texture object */ stObj = st_texture_object(att->Texture); /* point renderbuffer at texobject */ strb->rtt = stObj; strb->rtt_level = att->TextureLevel; strb->rtt_face = att->CubeMapFace; strb->rtt_slice = att->Zoffset; rb->Width = texImage->Width2; rb->Height = texImage->Height2; rb->_BaseFormat = texImage->_BaseFormat; rb->InternalFormat = texImage->InternalFormat; pipe_resource_reference( &strb->texture, pt ); pipe_surface_release(pipe, &strb->surface); assert(strb->rtt_level <= strb->texture->last_level); /* new surface for rendering into the texture */ memset(&surf_tmpl, 0, sizeof(surf_tmpl)); surf_tmpl.format = ctx->Color.sRGBEnabled ? strb->texture->format : util_format_linear(strb->texture->format); surf_tmpl.usage = PIPE_BIND_RENDER_TARGET; surf_tmpl.u.tex.level = strb->rtt_level; surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice; surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice; strb->surface = pipe->create_surface(pipe, strb->texture, &surf_tmpl); strb->Base.Format = st_pipe_format_to_mesa_format(pt->format); /* Invalidate buffer state so that the pipe's framebuffer state * gets updated. * That's where the new renderbuffer (which we just created) gets * passed to the pipe as a (color/depth) render target. */ st_invalidate_state(ctx, _NEW_BUFFERS); /* Need to trigger a call to update_framebuffer() since we just * attached a new renderbuffer. */ ctx->NewState |= _NEW_BUFFERS; }
/** * Called via ctx->Driver.Clear() */ static void st_Clear(struct gl_context *ctx, GLbitfield mask) { struct st_context *st = st_context(ctx); struct gl_renderbuffer *depthRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; struct gl_renderbuffer *stencilRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer; GLbitfield quad_buffers = 0x0; GLbitfield clear_buffers = 0x0; GLuint i; /* This makes sure the pipe has the latest scissor, etc values */ st_validate_state( st ); if (mask & BUFFER_BITS_COLOR) { for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { GLint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i]; if (b >= 0 && mask & (1 << b)) { struct gl_renderbuffer *rb = ctx->DrawBuffer->Attachment[b].Renderbuffer; struct st_renderbuffer *strb = st_renderbuffer(rb); int colormask_index = ctx->Extensions.EXT_draw_buffers2 ? i : 0; if (!strb || !strb->surface) continue; if (is_color_disabled(ctx, colormask_index)) continue; if (is_scissor_enabled(ctx, rb) || is_color_masked(ctx, colormask_index)) quad_buffers |= PIPE_CLEAR_COLOR0 << i; else clear_buffers |= PIPE_CLEAR_COLOR0 << i; } } } if (mask & BUFFER_BIT_DEPTH) { struct st_renderbuffer *strb = st_renderbuffer(depthRb); if (strb->surface && ctx->Depth.Mask) { if (is_scissor_enabled(ctx, depthRb)) quad_buffers |= PIPE_CLEAR_DEPTH; else clear_buffers |= PIPE_CLEAR_DEPTH; } } if (mask & BUFFER_BIT_STENCIL) { struct st_renderbuffer *strb = st_renderbuffer(stencilRb); if (strb->surface && !is_stencil_disabled(ctx, stencilRb)) { if (is_scissor_enabled(ctx, stencilRb) || is_stencil_masked(ctx, stencilRb)) quad_buffers |= PIPE_CLEAR_STENCIL; else clear_buffers |= PIPE_CLEAR_STENCIL; } } /* Always clear depth and stencil together. * This can only happen when the stencil writemask is not a full mask. */ if (quad_buffers & PIPE_CLEAR_DEPTHSTENCIL && clear_buffers & PIPE_CLEAR_DEPTHSTENCIL) { quad_buffers |= clear_buffers & PIPE_CLEAR_DEPTHSTENCIL; clear_buffers &= ~PIPE_CLEAR_DEPTHSTENCIL; } /* Only use quad-based clearing for the renderbuffers which cannot * use pipe->clear. We want to always use pipe->clear for the other * renderbuffers, because it's likely to be faster. */ if (quad_buffers) { clear_with_quad(ctx, quad_buffers); } if (clear_buffers) { /* We can't translate the clear color to the colorbuffer format, * because different colorbuffers may have different formats. */ st->pipe->clear(st->pipe, clear_buffers, (union pipe_color_union*)&ctx->Color.ClearColor, ctx->Depth.Clear, ctx->Stencil.Clear); } if (mask & BUFFER_BIT_ACCUM) _mesa_clear_accum_buffer(ctx); }
static void st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_query_object *stq = st_query_object(q); unsigned type; st_flush_bitmap_cache(st_context(ctx)); /* convert GL query type to Gallium query type */ switch (q->Target) { case GL_ANY_SAMPLES_PASSED: case GL_ANY_SAMPLES_PASSED_CONSERVATIVE: /* fall-through */ case GL_SAMPLES_PASSED_ARB: type = PIPE_QUERY_OCCLUSION_COUNTER; break; case GL_PRIMITIVES_GENERATED: type = PIPE_QUERY_PRIMITIVES_GENERATED; break; case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: type = PIPE_QUERY_PRIMITIVES_EMITTED; break; case GL_TIME_ELAPSED: if (st->has_time_elapsed) type = PIPE_QUERY_TIME_ELAPSED; else type = PIPE_QUERY_TIMESTAMP; break; default: assert(0 && "unexpected query target in st_BeginQuery()"); return; } if (stq->type != type) { /* free old query of different type */ if (stq->pq) { pipe->destroy_query(pipe, stq->pq); stq->pq = NULL; } if (stq->pq_begin) { pipe->destroy_query(pipe, stq->pq_begin); stq->pq_begin = NULL; } stq->type = PIPE_QUERY_TYPES; /* an invalid value */ } if (q->Target == GL_TIME_ELAPSED && type == PIPE_QUERY_TIMESTAMP) { /* Determine time elapsed by emitting two timestamp queries. */ if (!stq->pq_begin) { stq->pq_begin = pipe->create_query(pipe, type); stq->type = type; } pipe->end_query(pipe, stq->pq_begin); } else { if (!stq->pq) { stq->pq = pipe->create_query(pipe, type); stq->type = type; } pipe->begin_query(pipe, stq->pq); } assert(stq->type == type); }
static void accum_return(GLcontext *ctx, GLfloat value, GLint xpos, GLint ypos, GLint width, GLint height, struct st_renderbuffer *acc_strb, struct st_renderbuffer *color_strb) { struct pipe_context *pipe = ctx->st->pipe; struct pipe_screen *screen = pipe->screen; const GLubyte *colormask = ctx->Color.ColorMask; enum pipe_transfer_usage usage; struct pipe_transfer *color_trans; size_t stride = acc_strb->stride; const GLubyte *data = acc_strb->data; GLfloat *buf; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat)); if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) usage = PIPE_TRANSFER_READ_WRITE; else usage = PIPE_TRANSFER_WRITE; color_trans = st_cond_flush_get_tex_transfer(st_context(ctx), color_strb->texture, 0, 0, 0, usage, xpos, ypos, width, height); if (usage & PIPE_TRANSFER_READ) pipe_get_tile_rgba(color_trans, 0, 0, width, height, buf); switch (acc_strb->format) { case PIPE_FORMAT_R16G16B16A16_SNORM: { GLfloat *color = buf; int i, j, ch; for (i = 0; i < height; i++) { const GLshort *acc = (const GLshort *) (data + (ypos + i) * stride + xpos * 8); for (j = 0; j < width; j++) { for (ch = 0; ch < 4; ch++) { if (colormask[ch]) { GLfloat val = SHORT_TO_FLOAT(*acc * value); *color = CLAMP(val, 0.0f, 1.0f); } else { /* No change */ } ++acc; ++color; } } } } break; default: _mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()"); } pipe_put_tile_rgba(color_trans, 0, 0, width, height, buf); _mesa_free(buf); screen->tex_transfer_destroy(color_trans); }
/** * This uses a blit to copy the read buffer to a texture format which matches * the format and type combo and then a fast read-back is done using memcpy. * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is * a format which matches the swizzling. * * If such a format isn't available, we fall back to _mesa_readpixels. * * NOTE: Some drivers use a blit to convert between tiled and linear * texture layouts during texture uploads/downloads, so the blit * we do here should be free in such cases. */ static void st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid *pixels) { struct st_context *st = st_context(ctx); struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct pipe_resource *src; struct pipe_resource *dst = NULL; struct pipe_resource dst_templ; enum pipe_format dst_format, src_format; struct pipe_blit_info blit; unsigned bind = PIPE_BIND_TRANSFER_READ; struct pipe_transfer *tex_xfer; ubyte *map = NULL; /* Validate state (to be sure we have up-to-date framebuffer surfaces) * and flush the bitmap cache prior to reading. */ st_validate_state(st); st_flush_bitmap_cache(st); if (!st->prefer_blit_based_texture_transfer) { goto fallback; } /* This must be done after state validation. */ src = strb->texture; /* XXX Fallback for depth-stencil formats due to an incomplete * stencil blit implementation in some drivers. */ if (format == GL_DEPTH_STENCIL) { goto fallback; } /* We are creating a texture of the size of the region being read back. * Need to check for NPOT texture support. */ if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) && (!util_is_power_of_two(width) || !util_is_power_of_two(height))) { goto fallback; } /* If the base internal format and the texture format don't match, we have * to use the slow path. */ if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) { goto fallback; } /* See if the texture format already matches the format and type, * in which case the memcpy-based fast path will likely be used and * we don't have to blit. */ if (_mesa_format_matches_format_and_type(rb->Format, format, type, pack->SwapBytes)) { goto fallback; } if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) { goto fallback; } /* Convert the source format to what is expected by ReadPixels * and see if it's supported. */ src_format = util_format_linear(src->format); src_format = util_format_luminance_to_red(src_format); src_format = util_format_intensity_to_red(src_format); if (!src_format || !screen->is_format_supported(screen, src_format, src->target, src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) { goto fallback; } if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL) bind |= PIPE_BIND_DEPTH_STENCIL; else bind |= PIPE_BIND_RENDER_TARGET; /* Choose the destination format by finding the best match * for the format+type combo. */ dst_format = st_choose_matching_format(screen, bind, format, type, pack->SwapBytes); if (dst_format == PIPE_FORMAT_NONE) { goto fallback; } /* create the destination texture */ memset(&dst_templ, 0, sizeof(dst_templ)); dst_templ.target = PIPE_TEXTURE_2D; dst_templ.format = dst_format; dst_templ.bind = bind; dst_templ.usage = PIPE_USAGE_STAGING; st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1, &dst_templ.width0, &dst_templ.height0, &dst_templ.depth0, &dst_templ.array_size); dst = screen->resource_create(screen, &dst_templ); if (!dst) { goto fallback; } memset(&blit, 0, sizeof(blit)); blit.src.resource = src; blit.src.level = strb->surface->u.tex.level; blit.src.format = src_format; blit.dst.resource = dst; blit.dst.level = 0; blit.dst.format = dst->format; blit.src.box.x = x; blit.dst.box.x = 0; blit.src.box.y = y; blit.dst.box.y = 0; blit.src.box.z = strb->surface->u.tex.first_layer; 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 = st_get_blit_mask(rb->_BaseFormat, format); blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { blit.src.box.y = rb->Height - blit.src.box.y; blit.src.box.height = -blit.src.box.height; } /* blit */ st->pipe->blit(st->pipe, &blit); /* map resources */ pixels = _mesa_map_pbo_dest(ctx, pack, pixels); map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ, 0, 0, 0, width, height, 1, &tex_xfer); if (!map) { _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); goto fallback; } /* memcpy data into a user buffer */ { const uint bytesPerRow = width * util_format_get_blocksize(dst_format); GLuint row; for (row = 0; row < (unsigned) height; row++) { GLvoid *dest = _mesa_image_address3d(pack, pixels, width, height, format, type, 0, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } } pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); return; fallback: _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels); }
/** * Called via ctx->Driver.DeleteProgram() */ static void st_delete_program(struct gl_context *ctx, struct gl_program *prog) { struct st_context *st = st_context(ctx); switch( prog->Target ) { case GL_VERTEX_PROGRAM_ARB: { struct st_vertex_program *stvp = (struct st_vertex_program *) prog; st_release_vp_variants( st, stvp ); if (stvp->glsl_to_tgsi) free_glsl_to_tgsi_visitor(stvp->glsl_to_tgsi); } break; case GL_GEOMETRY_PROGRAM_NV: { struct st_geometry_program *stgp = (struct st_geometry_program *) prog; st_release_basic_variants(st, stgp->Base.Base.Target, &stgp->variants, &stgp->tgsi); if (stgp->glsl_to_tgsi) free_glsl_to_tgsi_visitor(stgp->glsl_to_tgsi); } break; case GL_FRAGMENT_PROGRAM_ARB: { struct st_fragment_program *stfp = (struct st_fragment_program *) prog; st_release_fp_variants(st, stfp); if (stfp->glsl_to_tgsi) free_glsl_to_tgsi_visitor(stfp->glsl_to_tgsi); } break; case GL_TESS_CONTROL_PROGRAM_NV: { struct st_tessctrl_program *sttcp = (struct st_tessctrl_program *) prog; st_release_basic_variants(st, sttcp->Base.Base.Target, &sttcp->variants, &sttcp->tgsi); if (sttcp->glsl_to_tgsi) free_glsl_to_tgsi_visitor(sttcp->glsl_to_tgsi); } break; case GL_TESS_EVALUATION_PROGRAM_NV: { struct st_tesseval_program *sttep = (struct st_tesseval_program *) prog; st_release_basic_variants(st, sttep->Base.Base.Target, &sttep->variants, &sttep->tgsi); if (sttep->glsl_to_tgsi) free_glsl_to_tgsi_visitor(sttep->glsl_to_tgsi); } break; case GL_COMPUTE_PROGRAM_NV: { struct st_compute_program *stcp = (struct st_compute_program *) prog; st_release_cp_variants(st, stcp); if (stcp->glsl_to_tgsi) free_glsl_to_tgsi_visitor(stcp->glsl_to_tgsi); } break; default: assert(0); /* problem */ } /* delete base class */ _mesa_delete_program( ctx, prog ); }
static void st_BlitFramebuffer(struct gl_context *ctx, struct gl_framebuffer *readFB, struct gl_framebuffer *drawFB, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { const GLbitfield depthStencil = (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); struct st_context *st = st_context(ctx); const uint pFilter = ((filter == GL_NEAREST) ? PIPE_TEX_FILTER_NEAREST : PIPE_TEX_FILTER_LINEAR); struct { GLint srcX0, srcY0, srcX1, srcY1; GLint dstX0, dstY0, dstX1, dstY1; } clip; struct pipe_blit_info blit; st_manager_validate_framebuffers(st); /* Make sure bitmap rendering has landed in the framebuffers */ st_flush_bitmap_cache(st); st_invalidate_readpix_cache(st); clip.srcX0 = srcX0; clip.srcY0 = srcY0; clip.srcX1 = srcX1; clip.srcY1 = srcY1; clip.dstX0 = dstX0; clip.dstY0 = dstY0; clip.dstX1 = dstX1; clip.dstY1 = dstY1; /* NOTE: If the src and dst dimensions don't match, we cannot simply adjust * the integer coordinates to account for clipping (or scissors) because that * would make us cut off fractional parts, affecting the result of the blit. * * XXX: This should depend on mask ! */ if (!_mesa_clip_blit(ctx, readFB, drawFB, &clip.srcX0, &clip.srcY0, &clip.srcX1, &clip.srcY1, &clip.dstX0, &clip.dstY0, &clip.dstX1, &clip.dstY1)) { return; /* nothing to draw/blit */ } memset(&blit, 0, sizeof(struct pipe_blit_info)); blit.scissor_enable = (dstX0 != clip.dstX0) || (dstY0 != clip.dstY0) || (dstX1 != clip.dstX1) || (dstY1 != clip.dstY1); if (st_fb_orientation(drawFB) == Y_0_TOP) { /* invert Y for dest */ dstY0 = drawFB->Height - dstY0; dstY1 = drawFB->Height - dstY1; /* invert Y for clip */ clip.dstY0 = drawFB->Height - clip.dstY0; clip.dstY1 = drawFB->Height - clip.dstY1; } if (blit.scissor_enable) { blit.scissor.minx = MIN2(clip.dstX0, clip.dstX1); blit.scissor.miny = MIN2(clip.dstY0, clip.dstY1); blit.scissor.maxx = MAX2(clip.dstX0, clip.dstX1); blit.scissor.maxy = MAX2(clip.dstY0, clip.dstY1); #if 0 debug_printf("scissor = (%i,%i)-(%i,%i)\n", blit.scissor.minx,blit.scissor.miny, blit.scissor.maxx,blit.scissor.maxy); #endif } if (st_fb_orientation(readFB) == Y_0_TOP) { /* invert Y for src */ srcY0 = readFB->Height - srcY0; srcY1 = readFB->Height - srcY1; } if (srcY0 > srcY1 && dstY0 > dstY1) { /* Both src and dst are upside down. Swap Y to make it * right-side up to increase odds of using a fast path. * Recall that all Gallium raster coords have Y=0=top. */ GLint tmp; tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } blit.src.box.depth = 1; blit.dst.box.depth = 1; /* Destination dimensions have to be positive: */ if (dstX0 < dstX1) { blit.dst.box.x = dstX0; blit.src.box.x = srcX0; blit.dst.box.width = dstX1 - dstX0; blit.src.box.width = srcX1 - srcX0; } else { blit.dst.box.x = dstX1; blit.src.box.x = srcX1; blit.dst.box.width = dstX0 - dstX1; blit.src.box.width = srcX0 - srcX1; } if (dstY0 < dstY1) { blit.dst.box.y = dstY0; blit.src.box.y = srcY0; blit.dst.box.height = dstY1 - dstY0; blit.src.box.height = srcY1 - srcY0; } else { blit.dst.box.y = dstY1; blit.src.box.y = srcY1; blit.dst.box.height = dstY0 - dstY1; blit.src.box.height = srcY0 - srcY1; } if (drawFB != ctx->WinSysDrawBuffer) st_window_rectangles_to_blit(ctx, &blit); blit.filter = pFilter; blit.render_condition_enable = TRUE; blit.alpha_blend = FALSE; if (mask & GL_COLOR_BUFFER_BIT) { struct gl_renderbuffer_attachment *srcAtt = &readFB->Attachment[readFB->_ColorReadBufferIndex]; blit.mask = PIPE_MASK_RGBA; if (srcAtt->Type == GL_TEXTURE) { struct st_texture_object *srcObj = st_texture_object(srcAtt->Texture); GLuint i; if (!srcObj || !srcObj->pt) { return; } for (i = 0; i < drawFB->_NumColorDrawBuffers; i++) { struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[i]); if (dstRb) { struct pipe_surface *dstSurf = dstRb->surface; if (dstSurf) { blit.dst.resource = dstSurf->texture; blit.dst.level = dstSurf->u.tex.level; blit.dst.box.z = dstSurf->u.tex.first_layer; blit.dst.format = dstSurf->format; blit.src.resource = srcObj->pt; blit.src.level = srcAtt->TextureLevel; blit.src.box.z = srcAtt->Zoffset + srcAtt->CubeMapFace; blit.src.format = srcObj->pt->format; st_adjust_blit_for_srgb(&blit, ctx->Color.sRGBEnabled); st->pipe->blit(st->pipe, &blit); dstRb->defined = true; /* front buffer tracking */ } } } } else { struct st_renderbuffer *srcRb = st_renderbuffer(readFB->_ColorReadBuffer); struct pipe_surface *srcSurf; GLuint i; if (!srcRb || !srcRb->surface) { return; } srcSurf = srcRb->surface; for (i = 0; i < drawFB->_NumColorDrawBuffers; i++) { struct st_renderbuffer *dstRb = st_renderbuffer(drawFB->_ColorDrawBuffers[i]); if (dstRb) { struct pipe_surface *dstSurf = dstRb->surface; if (dstSurf) { blit.dst.resource = dstSurf->texture; blit.dst.level = dstSurf->u.tex.level; blit.dst.box.z = dstSurf->u.tex.first_layer; blit.dst.format = dstSurf->format; blit.src.resource = srcSurf->texture; blit.src.level = srcSurf->u.tex.level; blit.src.box.z = srcSurf->u.tex.first_layer; blit.src.format = srcSurf->format; st_adjust_blit_for_srgb(&blit, ctx->Color.sRGBEnabled); st->pipe->blit(st->pipe, &blit); dstRb->defined = true; /* front buffer tracking */ } } } } } if (mask & depthStencil) { /* depth and/or stencil blit */ /* get src/dst depth surfaces */ struct st_renderbuffer *srcDepthRb = st_renderbuffer(readFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct st_renderbuffer *dstDepthRb = st_renderbuffer(drawFB->Attachment[BUFFER_DEPTH].Renderbuffer); struct pipe_surface *dstDepthSurf = dstDepthRb ? dstDepthRb->surface : NULL; struct st_renderbuffer *srcStencilRb = st_renderbuffer(readFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct st_renderbuffer *dstStencilRb = st_renderbuffer(drawFB->Attachment[BUFFER_STENCIL].Renderbuffer); struct pipe_surface *dstStencilSurf = dstStencilRb ? dstStencilRb->surface : NULL; if (_mesa_has_depthstencil_combined(readFB) && _mesa_has_depthstencil_combined(drawFB)) { blit.mask = 0; if (mask & GL_DEPTH_BUFFER_BIT) blit.mask |= PIPE_MASK_Z; if (mask & GL_STENCIL_BUFFER_BIT) blit.mask |= PIPE_MASK_S; blit.dst.resource = dstDepthSurf->texture; blit.dst.level = dstDepthSurf->u.tex.level; blit.dst.box.z = dstDepthSurf->u.tex.first_layer; blit.dst.format = dstDepthSurf->format; blit.src.resource = srcDepthRb->texture; blit.src.level = srcDepthRb->surface->u.tex.level; blit.src.box.z = srcDepthRb->surface->u.tex.first_layer; blit.src.format = srcDepthRb->surface->format; st->pipe->blit(st->pipe, &blit); } else { /* blitting depth and stencil separately */ if (mask & GL_DEPTH_BUFFER_BIT) { blit.mask = PIPE_MASK_Z; blit.dst.resource = dstDepthSurf->texture; blit.dst.level = dstDepthSurf->u.tex.level; blit.dst.box.z = dstDepthSurf->u.tex.first_layer; blit.dst.format = dstDepthSurf->format; blit.src.resource = srcDepthRb->texture; blit.src.level = srcDepthRb->surface->u.tex.level; blit.src.box.z = srcDepthRb->surface->u.tex.first_layer; blit.src.format = srcDepthRb->surface->format; st->pipe->blit(st->pipe, &blit); } if (mask & GL_STENCIL_BUFFER_BIT) { blit.mask = PIPE_MASK_S; blit.dst.resource = dstStencilSurf->texture; blit.dst.level = dstStencilSurf->u.tex.level; blit.dst.box.z = dstStencilSurf->u.tex.first_layer; blit.dst.format = dstStencilSurf->format; blit.src.resource = srcStencilRb->texture; blit.src.level = srcStencilRb->surface->u.tex.level; blit.src.box.z = srcStencilRb->surface->u.tex.first_layer; blit.src.format = srcStencilRb->surface->format; st->pipe->blit(st->pipe, &blit); } } } }
/** * Check that the framebuffer configuration is valid in terms of what * the driver can support. * * For Gallium we only supports combined Z+stencil, not separate buffers. */ static void st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) { struct st_context *st = st_context(ctx); struct pipe_screen *screen = st->pipe->screen; const struct gl_renderbuffer_attachment *depth = &fb->Attachment[BUFFER_DEPTH]; const struct gl_renderbuffer_attachment *stencil = &fb->Attachment[BUFFER_STENCIL]; GLuint i; enum pipe_format first_format = PIPE_FORMAT_NONE; boolean mixed_formats = screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0; if (depth->Type && stencil->Type && depth->Type != stencil->Type) { st_fbo_invalid("Different Depth/Stencil buffer formats"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } if (depth->Type == GL_RENDERBUFFER_EXT && stencil->Type == GL_RENDERBUFFER_EXT && depth->Renderbuffer != stencil->Renderbuffer) { st_fbo_invalid("Separate Depth/Stencil buffers"); fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } if (depth->Type == GL_TEXTURE && stencil->Type == GL_TEXTURE && depth->Texture != stencil->Texture) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; st_fbo_invalid("Different Depth/Stencil textures"); return; } if (!st_validate_attachment(ctx, screen, depth, PIPE_BIND_DEPTH_STENCIL)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } if (!st_validate_attachment(ctx, screen, stencil, PIPE_BIND_DEPTH_STENCIL)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } for (i = 0; i < ctx->Const.MaxColorAttachments; i++) { struct gl_renderbuffer_attachment *att = &fb->Attachment[BUFFER_COLOR0 + i]; enum pipe_format format; if (!st_validate_attachment(ctx, screen, att, PIPE_BIND_RENDER_TARGET)) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; return; } if (!mixed_formats) { /* Disallow mixed formats. */ if (att->Type != GL_NONE) { format = st_renderbuffer(att->Renderbuffer)->surface->format; } else { continue; } if (first_format == PIPE_FORMAT_NONE) { first_format = format; } else if (format != first_format) { fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT; st_fbo_invalid("Mixed color formats"); return; } } } }
/** * Called via ctx->Driver.MapRenderbuffer. */ static void st_MapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { struct st_context *st = st_context(ctx); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; const GLboolean invert = rb->Name == 0; unsigned usage; GLuint y2; GLubyte *map; if (strb->software) { /* software-allocated renderbuffer (probably an accum buffer) */ if (strb->data) { GLint bpp = _mesa_get_format_bytes(strb->Base.Format); GLint stride = _mesa_format_row_stride(strb->Base.Format, strb->Base.Width); *mapOut = (GLubyte *) strb->data + y * stride + x * bpp; *rowStrideOut = stride; } else { *mapOut = NULL; *rowStrideOut = 0; } return; } usage = 0x0; if (mode & GL_MAP_READ_BIT) usage |= PIPE_TRANSFER_READ; if (mode & GL_MAP_WRITE_BIT) usage |= PIPE_TRANSFER_WRITE; if (mode & GL_MAP_INVALIDATE_RANGE_BIT) usage |= PIPE_TRANSFER_DISCARD_RANGE; /* Note: y=0=bottom of buffer while y2=0=top of buffer. * 'invert' will be true for window-system buffers and false for * user-allocated renderbuffers and textures. */ if (invert) y2 = strb->Base.Height - y - h; else y2 = y; map = pipe_transfer_map(pipe, strb->texture, strb->surface->u.tex.level, strb->surface->u.tex.first_layer, usage, x, y2, w, h, &strb->transfer); if (map) { if (invert) { *rowStrideOut = -(int) strb->transfer->stride; map += (h - 1) * strb->transfer->stride; } else { *rowStrideOut = strb->transfer->stride; } *mapOut = map; } else { *mapOut = NULL; *rowStrideOut = 0; } }
static void st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access, GLboolean output, struct gl_texture_object *texObj, struct gl_texture_image *texImage, const GLvoid *vdpSurface, GLuint index) { int (*getProcAddr)(uint32_t device, uint32_t id, void **ptr); uint32_t device = (uintptr_t)ctx->vdpDevice; struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct st_texture_image *stImage = st_texture_image(texImage); struct pipe_resource *res; struct pipe_sampler_view *sv, templ; gl_format texFormat; getProcAddr = ctx->vdpGetProcAddress; if (output) { VdpOutputSurfaceGallium *f; if (getProcAddr(device, VDP_FUNC_ID_OUTPUT_SURFACE_GALLIUM, (void**)&f)) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } res = f((uintptr_t)vdpSurface); if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } } else { VdpVideoSurfaceGallium *f; struct pipe_video_buffer *buffer; struct pipe_sampler_view **samplers; if (getProcAddr(device, VDP_FUNC_ID_VIDEO_SURFACE_GALLIUM, (void**)&f)) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } buffer = f((uintptr_t)vdpSurface); if (!buffer) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } samplers = buffer->get_sampler_view_planes(buffer); if (!samplers) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } sv = samplers[index >> 1]; if (!sv) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } res = sv->texture; } if (!res) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* do we have different screen objects ? */ if (res->screen != st->pipe->screen) { _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV"); return; } /* switch to surface based */ if (!stObj->surface_based) { _mesa_clear_texture_object(ctx, texObj); stObj->surface_based = GL_TRUE; } texFormat = st_pipe_format_to_mesa_format(res->format); _mesa_init_teximage_fields(ctx, texImage, res->width0, res->height0, 1, 0, GL_RGBA, texFormat); pipe_resource_reference(&stObj->pt, res); pipe_sampler_view_reference(&stObj->sampler_view, NULL); pipe_resource_reference(&stImage->pt, res); u_sampler_view_default_template(&templ, res, res->format); templ.u.tex.first_layer = index & 1; templ.u.tex.last_layer = index & 1; templ.swizzle_r = GET_SWZ(stObj->base._Swizzle, 0); templ.swizzle_g = GET_SWZ(stObj->base._Swizzle, 1); templ.swizzle_b = GET_SWZ(stObj->base._Swizzle, 2); templ.swizzle_a = GET_SWZ(stObj->base._Swizzle, 3); stObj->sampler_view = st->pipe->create_sampler_view(st->pipe, res, &templ); stObj->width0 = res->width0; stObj->height0 = res->height0; stObj->depth0 = 1; stObj->surface_format = res->format; _mesa_dirty_texobj(ctx, texObj); }
/** * Called via ctx->Driver.GenerateMipmap(). */ void st_generate_mipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct st_context *st = st_context(ctx); struct st_texture_object *stObj = st_texture_object(texObj); struct pipe_resource *pt = st_get_texobj_resource(texObj); const uint baseLevel = texObj->BaseLevel; uint lastLevel, first_layer, last_layer; uint dstLevel; if (!pt) return; /* not sure if this ultimately actually should work, but we're not supporting multisampled textures yet. */ assert(pt->nr_samples < 2); /* find expected last mipmap level to generate*/ lastLevel = compute_num_levels(ctx, texObj, target) - 1; if (lastLevel == 0) return; /* The texture isn't in a "complete" state yet so set the expected * lastLevel here, since it won't get done in st_finalize_texture(). */ stObj->lastLevel = lastLevel; if (pt->last_level < lastLevel) { /* The current gallium texture doesn't have space for all the * mipmap levels we need to generate. So allocate a new texture. */ struct pipe_resource *oldTex = stObj->pt; /* create new texture with space for more levels */ stObj->pt = st_texture_create(st, oldTex->target, oldTex->format, lastLevel, oldTex->width0, oldTex->height0, oldTex->depth0, oldTex->array_size, 0, oldTex->bind); /* This will copy the old texture's base image into the new texture * which we just allocated. */ st_finalize_texture(ctx, st->pipe, texObj); /* release the old tex (will likely be freed too) */ pipe_resource_reference(&oldTex, NULL); st_texture_release_all_sampler_views(stObj); } else { /* Make sure that the base texture image data is present in the * texture buffer. */ st_finalize_texture(ctx, st->pipe, texObj); } pt = stObj->pt; assert(pt->last_level >= lastLevel); if (pt->target == PIPE_TEXTURE_CUBE) { first_layer = last_layer = _mesa_tex_target_to_face(target); } else { first_layer = 0; last_layer = util_max_layer(pt, baseLevel); } /* Try to generate the mipmap by rendering/texturing. If that fails, * use the software fallback. */ if (!util_gen_mipmap(st->pipe, pt, pt->format, baseLevel, lastLevel, first_layer, last_layer, PIPE_TEX_FILTER_LINEAR)) { _mesa_generate_mipmap(ctx, target, texObj); } /* Fill in the Mesa gl_texture_image fields */ for (dstLevel = baseLevel + 1; dstLevel <= lastLevel; dstLevel++) { const uint srcLevel = dstLevel - 1; const struct gl_texture_image *srcImage = _mesa_get_tex_image(ctx, texObj, target, srcLevel); struct gl_texture_image *dstImage; struct st_texture_image *stImage; uint border = srcImage->Border; uint dstWidth, dstHeight, dstDepth; dstWidth = u_minify(pt->width0, dstLevel); if (texObj->Target == GL_TEXTURE_1D_ARRAY) { dstHeight = pt->array_size; } else { dstHeight = u_minify(pt->height0, dstLevel); } if (texObj->Target == GL_TEXTURE_2D_ARRAY || texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) { dstDepth = pt->array_size; } else { dstDepth = u_minify(pt->depth0, dstLevel); } dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel); if (!dstImage) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "generating mipmaps"); return; } /* Free old image data */ ctx->Driver.FreeTextureImageBuffer(ctx, dstImage); /* initialize new image */ _mesa_init_teximage_fields(ctx, dstImage, dstWidth, dstHeight, dstDepth, border, srcImage->InternalFormat, srcImage->TexFormat); stImage = st_texture_image(dstImage); pipe_resource_reference(&stImage->pt, pt); } }
/** * Setup pipeline state prior to rendering the bitmap textured quad. */ static void setup_render_state(struct gl_context *ctx, struct pipe_sampler_view *sv, const GLfloat *color, bool atlas) { struct st_context *st = st_context(ctx); struct cso_context *cso = st->cso_context; struct st_fp_variant *fpv; struct st_fp_variant_key key; memset(&key, 0, sizeof(key)); key.st = st->has_shareable_shaders ? NULL : st; key.bitmap = GL_TRUE; key.clamp_color = st->clamp_frag_color_in_shader && ctx->Color._ClampFragmentColor; fpv = st_get_fp_variant(st, st->fp, &key); /* As an optimization, Mesa's fragment programs will sometimes get the * primary color from a statevar/constant rather than a varying variable. * when that's the case, we need to ensure that we use the 'color' * parameter and not the current attribute color (which may have changed * through glRasterPos and state validation. * So, we force the proper color here. Not elegant, but it works. */ { GLfloat colorSave[4]; COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color); st_upload_constants(st, st->fp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave); } cso_save_state(cso, (CSO_BIT_RASTERIZER | CSO_BIT_FRAGMENT_SAMPLERS | CSO_BIT_FRAGMENT_SAMPLER_VIEWS | CSO_BIT_VIEWPORT | CSO_BIT_STREAM_OUTPUTS | CSO_BIT_VERTEX_ELEMENTS | CSO_BIT_AUX_VERTEX_BUFFER_SLOT | CSO_BITS_ALL_SHADERS)); /* rasterizer state: just scissor */ st->bitmap.rasterizer.scissor = ctx->Scissor.EnableFlags & 1; cso_set_rasterizer(cso, &st->bitmap.rasterizer); /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, fpv->driver_shader); /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, st->bitmap.vs); /* disable other shaders */ cso_set_tessctrl_shader_handle(cso, NULL); cso_set_tesseval_shader_handle(cso, NULL); cso_set_geometry_shader_handle(cso, NULL); /* user samplers, plus our bitmap sampler */ { struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers[PIPE_SHADER_FRAGMENT]); uint i; for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++) { samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i]; } if (atlas) samplers[fpv->bitmap_sampler] = &st->bitmap.atlas_sampler; else samplers[fpv->bitmap_sampler] = &st->bitmap.sampler; cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, num, (const struct pipe_sampler_state **) samplers); } /* user textures, plus the bitmap texture */ { struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT], sizeof(sampler_views)); sampler_views[fpv->bitmap_sampler] = sv; cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, num, sampler_views); } /* viewport state: viewport matching window dims */ cso_set_viewport_dims(cso, st->state.framebuffer.width, st->state.framebuffer.height, st->state.fb_orientation == Y_0_TOP); cso_set_vertex_elements(cso, 3, st->util_velems); cso_set_stream_outputs(st->cso_context, 0, NULL, NULL); }
/** * Called via ctx->Driver.ProgramStringNotify() * Called when the program's text/code is changed. We have to free * all shader variants and corresponding gallium shaders when this happens. */ static GLboolean st_program_string_notify( struct gl_context *ctx, GLenum target, struct gl_program *prog ) { struct st_context *st = st_context(ctx); gl_shader_stage stage = _mesa_program_enum_to_shader_stage(target); if (target == GL_FRAGMENT_PROGRAM_ARB) { struct st_fragment_program *stfp = (struct st_fragment_program *) prog; st_release_fp_variants(st, stfp); if (!st_translate_fragment_program(st, stfp)) return false; if (st->fp == stfp) st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; } else if (target == GL_GEOMETRY_PROGRAM_NV) { struct st_geometry_program *stgp = (struct st_geometry_program *) prog; st_release_basic_variants(st, stgp->Base.Base.Target, &stgp->variants, &stgp->tgsi); if (!st_translate_geometry_program(st, stgp)) return false; if (st->gp == stgp) st->dirty.st |= ST_NEW_GEOMETRY_PROGRAM; } else if (target == GL_VERTEX_PROGRAM_ARB) { struct st_vertex_program *stvp = (struct st_vertex_program *) prog; st_release_vp_variants(st, stvp); if (!st_translate_vertex_program(st, stvp)) return false; if (st->vp == stvp) st->dirty.st |= ST_NEW_VERTEX_PROGRAM; } else if (target == GL_TESS_CONTROL_PROGRAM_NV) { struct st_tessctrl_program *sttcp = (struct st_tessctrl_program *) prog; st_release_basic_variants(st, sttcp->Base.Base.Target, &sttcp->variants, &sttcp->tgsi); if (!st_translate_tessctrl_program(st, sttcp)) return false; if (st->tcp == sttcp) st->dirty.st |= ST_NEW_TESSCTRL_PROGRAM; } else if (target == GL_TESS_EVALUATION_PROGRAM_NV) { struct st_tesseval_program *sttep = (struct st_tesseval_program *) prog; st_release_basic_variants(st, sttep->Base.Base.Target, &sttep->variants, &sttep->tgsi); if (!st_translate_tesseval_program(st, sttep)) return false; if (st->tep == sttep) st->dirty.st |= ST_NEW_TESSEVAL_PROGRAM; } else if (target == GL_COMPUTE_PROGRAM_NV) { struct st_compute_program *stcp = (struct st_compute_program *) prog; st_release_cp_variants(st, stcp); if (!st_translate_compute_program(st, stcp)) return false; if (st->cp == stcp) st->dirty_cp.st |= ST_NEW_COMPUTE_PROGRAM; } else if (target == GL_FRAGMENT_SHADER_ATI) { assert(prog); struct st_fragment_program *stfp = (struct st_fragment_program *) prog; assert(stfp->ati_fs); assert(stfp->ati_fs->Program == prog); st_init_atifs_prog(ctx, prog); st_release_fp_variants(st, stfp); if (!st_translate_fragment_program(st, stfp)) return false; if (st->fp == stfp) st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM; } if (ST_DEBUG & DEBUG_PRECOMPILE || st->shader_has_one_variant[stage]) st_precompile_shader_variant(st, prog); return GL_TRUE; }
/** * Called via ctx->Driver.DrawAtlasBitmap() */ static void st_DrawAtlasBitmaps(struct gl_context *ctx, const struct gl_bitmap_atlas *atlas, GLuint count, const GLubyte *ids) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_object *stObj = st_texture_object(atlas->texObj); struct pipe_sampler_view *sv; /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ const float z = ctx->Current.RasterPos[2] * 2.0f - 1.0f; const float *color = ctx->Current.RasterColor; const float clip_x_scale = 2.0f / st->state.framebuffer.width; const float clip_y_scale = 2.0f / st->state.framebuffer.height; const unsigned num_verts = count * 4; const unsigned num_vert_bytes = num_verts * sizeof(struct st_util_vertex); struct st_util_vertex *verts; struct pipe_vertex_buffer vb = {0}; unsigned i; if (!st->bitmap.cache) { init_bitmap_state(st); } st_flush_bitmap_cache(st); st_validate_state(st, ST_PIPELINE_RENDER); st_invalidate_readpix_cache(st); sv = st_create_texture_sampler_view(pipe, stObj->pt); if (!sv) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCallLists(bitmap text)"); return; } setup_render_state(ctx, sv, color, true); vb.stride = sizeof(struct st_util_vertex); u_upload_alloc(st->uploader, 0, num_vert_bytes, 4, &vb.buffer_offset, &vb.buffer, (void **) &verts); /* build quads vertex data */ for (i = 0; i < count; i++) { const GLfloat epsilon = 0.0001F; const struct gl_bitmap_glyph *g = &atlas->glyphs[ids[i]]; const float xmove = g->xmove, ymove = g->ymove; const float xorig = g->xorig, yorig = g->yorig; const float s0 = g->x, t0 = g->y; const float s1 = s0 + g->w, t1 = t0 + g->h; const float x0 = IFLOOR(ctx->Current.RasterPos[0] - xorig + epsilon); const float y0 = IFLOOR(ctx->Current.RasterPos[1] - yorig + epsilon); const float x1 = x0 + g->w, y1 = y0 + g->h; const float clip_x0 = x0 * clip_x_scale - 1.0f; const float clip_y0 = y0 * clip_y_scale - 1.0f; const float clip_x1 = x1 * clip_x_scale - 1.0f; const float clip_y1 = y1 * clip_y_scale - 1.0f; /* lower-left corner */ verts->x = clip_x0; verts->y = clip_y0; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s0; verts->t = t0; verts++; /* lower-right corner */ verts->x = clip_x1; verts->y = clip_y0; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s1; verts->t = t0; verts++; /* upper-right corner */ verts->x = clip_x1; verts->y = clip_y1; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s1; verts->t = t1; verts++; /* upper-left corner */ verts->x = clip_x0; verts->y = clip_y1; verts->z = z; verts->r = color[0]; verts->g = color[1]; verts->b = color[2]; verts->a = color[3]; verts->s = s0; verts->t = t1; verts++; /* Update the raster position */ ctx->Current.RasterPos[0] += xmove; ctx->Current.RasterPos[1] += ymove; } u_upload_unmap(st->uploader); cso_set_vertex_buffers(st->cso_context, cso_get_aux_vertex_buffer_slot(st->cso_context), 1, &vb); cso_draw_arrays(st->cso_context, PIPE_PRIM_QUADS, 0, num_verts); restore_render_state(ctx); pipe_resource_reference(&vb.buffer, NULL); pipe_sampler_view_reference(&sv, NULL); /* We uploaded modified constants, need to invalidate them. */ st->dirty |= ST_NEW_FS_CONSTANTS; }
/** * Translate Mesa program to TGSI format. * \param program the program to translate * \param numInputs number of input registers used * \param inputMapping maps Mesa fragment program inputs to TGSI generic * input indexes * \param inputSemanticName the TGSI_SEMANTIC flag for each input * \param inputSemanticIndex the semantic index (ex: which texcoord) for * each input * \param interpMode the TGSI_INTERPOLATE_LINEAR/PERSP mode for each input * \param numOutputs number of output registers used * \param outputMapping maps Mesa fragment program outputs to TGSI * generic outputs * \param outputSemanticName the TGSI_SEMANTIC flag for each output * \param outputSemanticIndex the semantic index (ex: which texcoord) for * each output * * \return PIPE_OK or PIPE_ERROR_OUT_OF_MEMORY */ enum pipe_error st_translate_mesa_program( struct gl_context *ctx, uint procType, struct ureg_program *ureg, const struct gl_program *program, GLuint numInputs, const GLuint inputMapping[], const ubyte inputSemanticName[], const ubyte inputSemanticIndex[], const GLuint interpMode[], GLuint numOutputs, const GLuint outputMapping[], const ubyte outputSemanticName[], const ubyte outputSemanticIndex[], boolean passthrough_edgeflags, boolean clamp_color) { struct st_translate translate, *t; unsigned i; enum pipe_error ret = PIPE_OK; assert(numInputs <= ARRAY_SIZE(t->inputs)); assert(numOutputs <= ARRAY_SIZE(t->outputs)); t = &translate; memset(t, 0, sizeof *t); t->procType = procType; t->inputMapping = inputMapping; t->outputMapping = outputMapping; t->ureg = ureg; /*_mesa_print_program(program);*/ /* * Declare input attributes. */ if (procType == TGSI_PROCESSOR_FRAGMENT) { for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_fs_input(ureg, inputSemanticName[i], inputSemanticIndex[i], interpMode[i]); } if (program->InputsRead & VARYING_BIT_POS) { /* Must do this after setting up t->inputs, and before * emitting constant references, below: */ emit_wpos(st_context(ctx), t, program, ureg); } if (program->InputsRead & VARYING_BIT_FACE) { emit_face_var( t, program ); } /* * Declare output attributes. */ for (i = 0; i < numOutputs; i++) { switch (outputSemanticName[i]) { case TGSI_SEMANTIC_POSITION: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, /* Z / Depth */ outputSemanticIndex[i] ); t->outputs[i] = ureg_writemask( t->outputs[i], TGSI_WRITEMASK_Z ); break; case TGSI_SEMANTIC_STENCIL: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_STENCIL, /* Stencil */ outputSemanticIndex[i] ); t->outputs[i] = ureg_writemask( t->outputs[i], TGSI_WRITEMASK_Y ); break; case TGSI_SEMANTIC_COLOR: t->outputs[i] = ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, outputSemanticIndex[i] ); break; default: debug_assert(0); return 0; } } } else if (procType == TGSI_PROCESSOR_GEOMETRY) { for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_input(ureg, inputSemanticName[i], inputSemanticIndex[i], 0, 1); } for (i = 0; i < numOutputs; i++) { t->outputs[i] = ureg_DECL_output( ureg, outputSemanticName[i], outputSemanticIndex[i] ); } } else { assert(procType == TGSI_PROCESSOR_VERTEX); for (i = 0; i < numInputs; i++) { t->inputs[i] = ureg_DECL_vs_input(ureg, i); } for (i = 0; i < numOutputs; i++) { t->outputs[i] = ureg_DECL_output( ureg, outputSemanticName[i], outputSemanticIndex[i] ); if (outputSemanticName[i] == TGSI_SEMANTIC_FOG) { /* force register to contain a fog coordinate in the form (F, 0, 0, 1). */ ureg_MOV(ureg, ureg_writemask(t->outputs[i], TGSI_WRITEMASK_YZW), ureg_imm4f(ureg, 0.0f, 0.0f, 0.0f, 1.0f)); t->outputs[i] = ureg_writemask(t->outputs[i], TGSI_WRITEMASK_X); } } if (passthrough_edgeflags) emit_edgeflags( t, program ); } /* Declare address register. */ if (program->NumAddressRegs > 0) { debug_assert( program->NumAddressRegs == 1 ); t->address[0] = ureg_DECL_address( ureg ); } /* Declare misc input registers */ { GLbitfield sysInputs = program->SystemValuesRead; unsigned numSys = 0; for (i = 0; sysInputs; i++) { if (sysInputs & (1 << i)) { unsigned semName = _mesa_sysval_to_semantic[i]; t->systemValues[i] = ureg_DECL_system_value(ureg, numSys, semName, 0); if (semName == TGSI_SEMANTIC_INSTANCEID || semName == TGSI_SEMANTIC_VERTEXID) { /* From Gallium perspective, these system values are always * integer, and require native integer support. However, if * native integer is supported on the vertex stage but not the * pixel stage (e.g, i915g + draw), Mesa will generate IR that * assumes these system values are floats. To resolve the * inconsistency, we insert a U2F. */ struct st_context *st = st_context(ctx); struct pipe_screen *pscreen = st->pipe->screen; assert(procType == TGSI_PROCESSOR_VERTEX); assert(pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_INTEGERS)); (void) pscreen; /* silence non-debug build warnings */ if (!ctx->Const.NativeIntegers) { struct ureg_dst temp = ureg_DECL_local_temporary(t->ureg); ureg_U2F( t->ureg, ureg_writemask(temp, TGSI_WRITEMASK_X), t->systemValues[i]); t->systemValues[i] = ureg_scalar(ureg_src(temp), 0); } } numSys++; sysInputs &= ~(1 << i); } } } if (program->IndirectRegisterFiles & (1 << PROGRAM_TEMPORARY)) { /* If temps are accessed with indirect addressing, declare temporaries * in sequential order. Else, we declare them on demand elsewhere. */ for (i = 0; i < program->NumTemporaries; i++) { /* XXX use TGSI_FILE_TEMPORARY_ARRAY when it's supported by ureg */ t->temps[i] = ureg_DECL_temporary( t->ureg ); } } /* Emit constants and immediates. Mesa uses a single index space * for these, so we put all the translated regs in t->constants. */ if (program->Parameters) { t->constants = calloc( program->Parameters->NumParameters, sizeof t->constants[0] ); if (t->constants == NULL) { ret = PIPE_ERROR_OUT_OF_MEMORY; goto out; } for (i = 0; i < program->Parameters->NumParameters; i++) { switch (program->Parameters->Parameters[i].Type) { case PROGRAM_STATE_VAR: case PROGRAM_UNIFORM: t->constants[i] = ureg_DECL_constant( ureg, i ); break; /* Emit immediates only when there's no indirect addressing of * the const buffer. * FIXME: Be smarter and recognize param arrays: * indirect addressing is only valid within the referenced * array. */ case PROGRAM_CONSTANT: if (program->IndirectRegisterFiles & PROGRAM_ANY_CONST) t->constants[i] = ureg_DECL_constant( ureg, i ); else t->constants[i] = ureg_DECL_immediate( ureg, (const float*) program->Parameters->ParameterValues[i], 4 ); break; default: break; } } } /* texture samplers */ for (i = 0; i < ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits; i++) { if (program->SamplersUsed & (1 << i)) { t->samplers[i] = ureg_DECL_sampler( ureg, i ); } } /* Emit each instruction in turn: */ for (i = 0; i < program->NumInstructions; i++) { set_insn_start( t, ureg_get_instruction_number( ureg )); compile_instruction( ctx, t, &program->Instructions[i], clamp_color ); } /* Fix up all emitted labels: */ for (i = 0; i < t->labels_count; i++) { ureg_fixup_label( ureg, t->labels[i].token, t->insn[t->labels[i].branch_target] ); } out: free(t->insn); free(t->labels); free(t->constants); if (t->error) { debug_printf("%s: translate error flag set\n", __func__); } return ret; }
/** * Do glClear by drawing a quadrilateral. * The vertices of the quad will be computed from the * ctx->DrawBuffer->_X/Ymin/max fields. */ static void clear_with_quad(struct gl_context *ctx, unsigned clear_buffers) { struct st_context *st = st_context(ctx); const struct gl_framebuffer *fb = ctx->DrawBuffer; const GLfloat fb_width = (GLfloat) fb->Width; const GLfloat fb_height = (GLfloat) fb->Height; const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin / fb_width * 2.0f - 1.0f; const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax / fb_width * 2.0f - 1.0f; const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin / fb_height * 2.0f - 1.0f; const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax / fb_height * 2.0f - 1.0f; unsigned num_layers = util_framebuffer_get_num_layers(&st->state.framebuffer); /* printf("%s %s%s%s %f,%f %f,%f\n", __FUNCTION__, color ? "color, " : "", depth ? "depth, " : "", stencil ? "stencil" : "", x0, y0, x1, y1); */ cso_save_blend(st->cso_context); cso_save_stencil_ref(st->cso_context); cso_save_depth_stencil_alpha(st->cso_context); cso_save_rasterizer(st->cso_context); cso_save_sample_mask(st->cso_context); cso_save_viewport(st->cso_context); cso_save_fragment_shader(st->cso_context); cso_save_stream_outputs(st->cso_context); cso_save_vertex_shader(st->cso_context); cso_save_geometry_shader(st->cso_context); cso_save_vertex_elements(st->cso_context); cso_save_aux_vertex_buffer_slot(st->cso_context); /* blend state: RGBA masking */ { struct pipe_blend_state blend; memset(&blend, 0, sizeof(blend)); if (clear_buffers & PIPE_CLEAR_COLOR) { int num_buffers = ctx->Extensions.EXT_draw_buffers2 ? ctx->DrawBuffer->_NumColorDrawBuffers : 1; int i; blend.independent_blend_enable = num_buffers > 1; for (i = 0; i < num_buffers; i++) { if (!(clear_buffers & (PIPE_CLEAR_COLOR0 << i))) continue; if (ctx->Color.ColorMask[i][0]) blend.rt[i].colormask |= PIPE_MASK_R; if (ctx->Color.ColorMask[i][1]) blend.rt[i].colormask |= PIPE_MASK_G; if (ctx->Color.ColorMask[i][2]) blend.rt[i].colormask |= PIPE_MASK_B; if (ctx->Color.ColorMask[i][3]) blend.rt[i].colormask |= PIPE_MASK_A; } if (st->ctx->Color.DitherFlag) blend.dither = 1; } cso_set_blend(st->cso_context, &blend); } /* depth_stencil state: always pass/set to ref value */ { struct pipe_depth_stencil_alpha_state depth_stencil; memset(&depth_stencil, 0, sizeof(depth_stencil)); if (clear_buffers & PIPE_CLEAR_DEPTH) { depth_stencil.depth.enabled = 1; depth_stencil.depth.writemask = 1; depth_stencil.depth.func = PIPE_FUNC_ALWAYS; } if (clear_buffers & PIPE_CLEAR_STENCIL) { struct pipe_stencil_ref stencil_ref; memset(&stencil_ref, 0, sizeof(stencil_ref)); depth_stencil.stencil[0].enabled = 1; depth_stencil.stencil[0].func = PIPE_FUNC_ALWAYS; depth_stencil.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; depth_stencil.stencil[0].valuemask = 0xff; depth_stencil.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; stencil_ref.ref_value[0] = ctx->Stencil.Clear; cso_set_stencil_ref(st->cso_context, &stencil_ref); } cso_set_depth_stencil_alpha(st->cso_context, &depth_stencil); } cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw); cso_set_stream_outputs(st->cso_context, 0, NULL, NULL); cso_set_sample_mask(st->cso_context, ~0); cso_set_rasterizer(st->cso_context, &st->clear.raster); /* viewport state: viewport matching window dims */ { const GLboolean invert = (st_fb_orientation(fb) == Y_0_TOP); struct pipe_viewport_state vp; vp.scale[0] = 0.5f * fb_width; vp.scale[1] = fb_height * (invert ? -0.5f : 0.5f); vp.scale[2] = 1.0f; vp.scale[3] = 1.0f; vp.translate[0] = 0.5f * fb_width; vp.translate[1] = 0.5f * fb_height; vp.translate[2] = 0.0f; vp.translate[3] = 0.0f; cso_set_viewport(st->cso_context, &vp); } set_fragment_shader(st); cso_set_geometry_shader_handle(st->cso_context, NULL); if (num_layers > 1) set_vertex_shader_layered(st); else set_vertex_shader(st); /* We can't translate the clear color to the colorbuffer format, * because different colorbuffers may have different formats. */ /* draw quad matching scissor rect */ draw_quad(st, x0, y0, x1, y1, (GLfloat) ctx->Depth.Clear, num_layers, (union pipe_color_union*)&ctx->Color.ClearColor); /* Restore pipe state */ cso_restore_blend(st->cso_context); cso_restore_stencil_ref(st->cso_context); cso_restore_depth_stencil_alpha(st->cso_context); cso_restore_rasterizer(st->cso_context); cso_restore_sample_mask(st->cso_context); cso_restore_viewport(st->cso_context); cso_restore_fragment_shader(st->cso_context); cso_restore_vertex_shader(st->cso_context); cso_restore_geometry_shader(st->cso_context); cso_restore_vertex_elements(st->cso_context); cso_restore_aux_vertex_buffer_slot(st->cso_context); cso_restore_stream_outputs(st->cso_context); }