/* Copy mipmap image between trees */ void intel_miptree_image_copy(struct intel_context *intel, struct intel_mipmap_tree *dst, GLuint face, GLuint level, struct intel_mipmap_tree *src) { GLuint width = src->level[level].width; GLuint height = src->level[level].height; GLuint depth = src->level[level].depth; GLuint dst_offset = intel_miptree_image_offset(dst, face, level); GLuint src_offset = intel_miptree_image_offset(src, face, level); const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); GLuint i; if (dst->compressed) { GLuint alignment = intel_compressed_alignment(dst->internal_format); height = (height + 3) / 4; width = ((width + alignment - 1) & ~(alignment - 1)); } for (i = 0; i < depth; i++) { intel_region_copy(intel, dst->region, dst_offset + dst_depth_offset[i], 0, 0, src->region, src_offset + src_depth_offset[i], 0, 0, width, height); } }
/* Copy mipmap image between trees */ void intel_miptree_image_copy(struct intel_context *intel, struct intel_mipmap_tree *dst, GLuint face, GLuint level, struct intel_mipmap_tree *src) { GLuint width = src->level[level].width; GLuint height = src->level[level].height; GLuint depth = src->level[level].depth; GLuint dst_offset = intel_miptree_image_offset(dst, face, level); GLuint src_offset = intel_miptree_image_offset(src, face, level); const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); GLuint i; if (dst->compressed) height /= 4; for (i = 0; i < depth; i++) { intel_region_copy(intel->intelScreen, dst->region, dst_offset + dst_depth_offset[i], 0, 0, src->region, src_offset + src_depth_offset[i], 0, 0, width, height); } }
/* Upload data for a particular image. */ void intel_miptree_image_data(struct intel_context *intel, struct intel_mipmap_tree *dst, GLuint face, GLuint level, void *src, GLuint src_row_pitch, GLuint src_image_pitch) { GLuint depth = dst->level[level].depth; GLuint dst_offset = intel_miptree_image_offset(dst, face, level); const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); GLuint i; GLuint height = 0; DBG("%s: %d/%d\n", __FUNCTION__, face, level); for (i = 0; i < depth; i++) { height = dst->level[level].height; if(dst->compressed) height = (height + 3) / 4; intel_region_data(intel, dst->region, dst_offset + dst_depth_offset[i], /* dst_offset */ 0, 0, /* dstx, dsty */ src, src_row_pitch, 0, 0, /* source x, y */ dst->level[level].width, height); /* width, height */ src += src_image_pitch * dst->cpp; } }
/** * Map a teximage in a mipmap tree. * \param row_stride returns row stride in bytes * \param image_stride returns image stride in bytes (for 3D textures). * \param image_offsets pointer to array of pixel offsets from the returned * pointer to each depth image * \return address of mapping */ GLubyte * intel_miptree_image_map(struct intel_context * intel, struct intel_mipmap_tree * mt, GLuint face, GLuint level, GLuint * row_stride, GLuint * image_offsets) { DBG("%s \n", __FUNCTION__); if (row_stride) *row_stride = mt->pitch * mt->cpp; if (mt->target == GL_TEXTURE_3D) { int i; for (i = 0; i < mt->level[level].depth; i++) image_offsets[i] = mt->level[level].image_offset[i] / mt->cpp; } else { assert(mt->level[level].depth == 1); assert(mt->target == GL_TEXTURE_CUBE_MAP || mt->level[level].image_offset[0] == 0); image_offsets[0] = 0; } return (intel_region_map(intel, mt->region) + intel_miptree_image_offset(mt, face, level)); }
/* XXX: Do this for TexSubImage also: */ static GLboolean try_pbo_upload(struct intel_context *intel, struct intel_texture_image *intelImage, const struct gl_pixelstore_attrib *unpack, GLint internalFormat, GLint width, GLint height, GLenum format, GLenum type, const void *pixels) { struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); GLuint src_offset, src_stride; GLuint dst_offset, dst_stride; if (!pbo || intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { _mesa_printf("%s: failure 1\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) pixels; if (unpack->RowLength > 0) src_stride = unpack->RowLength; else src_stride = width; dst_offset = intel_miptree_image_offset(intelImage->mt, intelImage->face, intelImage->level); dst_stride = intelImage->mt->pitch; intelFlush(&intel->ctx); LOCK_HARDWARE(intel); { struct _DriBufferObject *src_buffer = intel_bufferobj_buffer(intel, pbo, INTEL_READ); struct _DriBufferObject *dst_buffer = intel_region_buffer(intel->intelScreen, intelImage->mt->region, INTEL_WRITE_FULL); intelEmitCopyBlit(intel, intelImage->mt->cpp, src_stride, src_buffer, src_offset, dst_stride, dst_buffer, dst_offset, 0, 0, 0, 0, width, height, GL_COPY); intel_batchbuffer_flush(intel->batch); } UNLOCK_HARDWARE(intel); return GL_TRUE; }
/** * Map a teximage in a mipmap tree. * \param row_stride returns row stride in bytes * \param image_stride returns image stride in bytes (for 3D textures). * \return address of mapping */ GLubyte * intel_miptree_image_map(struct intel_context * intel, struct intel_mipmap_tree * mt, GLuint face, GLuint level, GLuint * row_stride, GLuint * image_offsets) { DBG("%s \n", __FUNCTION__); if (row_stride) *row_stride = mt->pitch * mt->cpp; if (image_offsets) memcpy(image_offsets, mt->level[level].image_offset, mt->level[level].depth * sizeof(GLuint)); return (intel_region_map(intel->intelScreen, mt->region) + intel_miptree_image_offset(mt, face, level)); }
static GLboolean try_pbo_zcopy(struct intel_context *intel, struct intel_texture_image *intelImage, const struct gl_pixelstore_attrib *unpack, GLint internalFormat, GLint width, GLint height, GLenum format, GLenum type, const void *pixels) { struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); GLuint src_offset, src_stride; GLuint dst_offset, dst_stride; if (!pbo || intel->ctx._ImageTransferState || unpack->SkipPixels || unpack->SkipRows) { _mesa_printf("%s: failure 1\n", __FUNCTION__); return GL_FALSE; } src_offset = (GLuint) pixels; if (unpack->RowLength > 0) src_stride = unpack->RowLength; else src_stride = width; dst_offset = intel_miptree_image_offset(intelImage->mt, intelImage->face, intelImage->level); dst_stride = intelImage->mt->pitch; if (src_stride != dst_stride || dst_offset != 0 || src_offset != 0) { _mesa_printf("%s: failure 2\n", __FUNCTION__); return GL_FALSE; } intel_region_attach_pbo(intel->intelScreen, intelImage->mt->region, pbo); return GL_TRUE; }
/* Recalculate all state from scratch. Perhaps not the most * efficient, but this has gotten complex enough that we need * something which is understandable and reliable. */ static GLboolean i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) { GLcontext *ctx = &intel->ctx; struct i830_context *i830 = i830_context(ctx); struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; struct intel_texture_object *intelObj = intel_texture_object(tObj); struct gl_texture_image *firstImage; GLuint *state = i830->state.Tex[unit], format, pitch; memset(state, 0, sizeof(state)); /*We need to refcount these. */ if (i830->state.tex_buffer[unit] != NULL) { dri_bo_unreference(i830->state.tex_buffer[unit]); i830->state.tex_buffer[unit] = NULL; } if (!intelObj->imageOverride && !intel_finalize_mipmap_tree(intel, unit)) return GL_FALSE; /* Get first image here, since intelObj->firstLevel will get set in * the intel_finalize_mipmap_tree() call above. */ firstImage = tObj->Image[0][intelObj->firstLevel]; if (intelObj->imageOverride) { i830->state.tex_buffer[unit] = NULL; i830->state.tex_offset[unit] = intelObj->textureOffset; switch (intelObj->depthOverride) { case 32: format = MAPSURF_32BIT | MT_32BIT_ARGB8888; break; case 24: default: format = MAPSURF_32BIT | MT_32BIT_XRGB8888; break; case 16: format = MAPSURF_16BIT | MT_16BIT_RGB565; break; } pitch = intelObj->pitchOverride; } else { dri_bo_reference(intelObj->mt->region->buffer); i830->state.tex_buffer[unit] = intelObj->mt->region->buffer; i830->state.tex_offset[unit] = intel_miptree_image_offset(intelObj->mt, 0, intelObj-> firstLevel); format = translate_texture_format(firstImage->TexFormat->MesaFormat); pitch = intelObj->mt->pitch * intelObj->mt->cpp; } state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | (LOAD_TEXTURE_MAP0 << unit) | 4); /* state[I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE | */ /* t->intel.TextureOffset); */ state[I830_TEXREG_TM0S1] = (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) | ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | format); state[I830_TEXREG_TM0S2] = ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); { if (tObj->Target == GL_TEXTURE_CUBE_MAP) state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) | CUBE_NEGX_ENABLE | CUBE_POSX_ENABLE | CUBE_NEGY_ENABLE | CUBE_POSY_ENABLE | CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE); else state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit)); } { GLuint minFilt, mipFilt, magFilt; switch (tObj->MinFilter) { case GL_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NONE; break; case GL_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NONE; break; case GL_NEAREST_MIPMAP_NEAREST: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_NEAREST; break; case GL_LINEAR_MIPMAP_NEAREST: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_NEAREST; break; case GL_NEAREST_MIPMAP_LINEAR: minFilt = FILTER_NEAREST; mipFilt = MIPFILTER_LINEAR; break; case GL_LINEAR_MIPMAP_LINEAR: minFilt = FILTER_LINEAR; mipFilt = MIPFILTER_LINEAR; break; default: return GL_FALSE; } if (tObj->MaxAnisotropy > 1.0) { minFilt = FILTER_ANISOTROPIC; magFilt = FILTER_ANISOTROPIC; } else { switch (tObj->MagFilter) { case GL_NEAREST: magFilt = FILTER_NEAREST; break; case GL_LINEAR: magFilt = FILTER_LINEAR; break; default: return GL_FALSE; } } state[I830_TEXREG_TM0S3] = i830->lodbias_tm0s3[unit]; #if 0 /* YUV conversion: */ if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR || firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV) state[I830_TEXREG_TM0S3] |= SS2_COLORSPACE_CONVERSION; #endif state[I830_TEXREG_TM0S3] |= ((intelObj->lastLevel - intelObj->firstLevel) * 4) << TM0S3_MIN_MIP_SHIFT; state[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) | (mipFilt << TM0S3_MIP_FILTER_SHIFT) | (magFilt << TM0S3_MAG_FILTER_SHIFT)); } { GLenum ws = tObj->WrapS; GLenum wt = tObj->WrapT; /* 3D textures not available on i830 */ if (tObj->Target == GL_TEXTURE_3D) return GL_FALSE; state[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD | MAP_UNIT(unit) | ENABLE_TEXCOORD_PARAMS | ss3 | ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(translate_wrap_mode(wt)) | ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(translate_wrap_mode (ws))); } state[I830_TEXREG_TM0S4] = INTEL_PACKCOLOR8888(tObj->_BorderChan[0], tObj->_BorderChan[1], tObj->_BorderChan[2], tObj->_BorderChan[3]); I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), GL_TRUE); /* memcmp was already disabled, but definitely won't work as the * region might now change and that wouldn't be detected: */ I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); return GL_TRUE; }
static GLboolean do_copy_texsubimage(struct intel_context *intel, struct intel_texture_image *intelImage, GLenum internalFormat, GLint dstx, GLint dsty, GLint x, GLint y, GLsizei width, GLsizei height) { GLcontext *ctx = &intel->ctx; const struct intel_region *src = get_teximage_source(intel, internalFormat); if (!intelImage->mt || !src) { DBG("%s fail %p %p\n", __FUNCTION__, intelImage->mt, src); return GL_FALSE; } intelFlush(ctx); LOCK_HARDWARE(intel); { GLuint image_offset = intel_miptree_image_offset(intelImage->mt, intelImage->face, intelImage->level); const GLint orig_x = x; const GLint orig_y = y; const struct gl_framebuffer *fb = ctx->DrawBuffer; if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, &x, &y, &width, &height)) { /* Update dst for clipped src. Need to also clip the source rect. */ dstx += x - orig_x; dsty += y - orig_y; if (ctx->ReadBuffer->Name == 0) { /* reading from a window, adjust x, y */ __DRIdrawablePrivate *dPriv = intel->driDrawable; GLuint window_y; /* window_y = position of window on screen if y=0=bottom */ window_y = intel->intelScreen->height - (dPriv->y + dPriv->h); y = window_y + y; x += dPriv->x; } else { /* reading from a FBO */ /* invert Y */ y = ctx->ReadBuffer->Height - y - 1; } /* A bit of fiddling to get the blitter to work with -ve * pitches. But we get a nice inverted blit this way, so it's * worth it: */ intelEmitCopyBlit(intel, intelImage->mt->cpp, -src->pitch, src->buffer, src->height * src->pitch * src->cpp, intelImage->mt->pitch, intelImage->mt->region->buffer, image_offset, x, y + height, dstx, dsty, width, height, GL_COPY); /* ? */ intel_batchbuffer_flush(intel->batch); } } UNLOCK_HARDWARE(intel); #if 0 /* GL_SGIS_generate_mipmap -- this can be accelerated now. * XXX Add a ctx->Driver.GenerateMipmaps() function? */ if (level == texObj->BaseLevel && texObj->GenerateMipmap) { intel_generate_mipmap(ctx, target, &ctx->Texture.Unit[ctx->Texture.CurrentUnit], texObj); } #endif return GL_TRUE; }
/** * Called by glFramebufferTexture[123]DEXT() (and other places) to * prepare for rendering into texture memory. This might be called * many times to choose different texture levels, cube faces, etc * before intel_finish_render_texture() is ever called. */ static void intel_render_texture(GLcontext * ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att) { struct gl_texture_image *newImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); struct intel_texture_image *intel_image; GLuint imageOffset; (void) fb; ASSERT(newImage); if (!irb) { irb = intel_wrap_texture(ctx, newImage); if (irb) { /* bind the wrapper to the attachment point */ _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base); } else { /* fallback to software rendering */ _mesa_render_texture(ctx, fb, att); return; } } if (!intel_update_wrapper(ctx, irb, newImage)) { _mesa_reference_renderbuffer(&att->Renderbuffer, NULL); _mesa_render_texture(ctx, fb, att); return; } DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n", _glthread_GetID(), att->Texture->Name, newImage->Width, newImage->Height, irb->Base.RefCount); /* point the renderbufer's region to the texture image region */ intel_image = intel_texture_image(newImage); if (irb->region != intel_image->mt->region) { if (irb->region) intel_region_release(&irb->region); intel_region_reference(&irb->region, intel_image->mt->region); } /* compute offset of the particular 2D image within the texture region */ imageOffset = intel_miptree_image_offset(intel_image->mt, att->CubeMapFace, att->TextureLevel); if (att->Texture->Target == GL_TEXTURE_3D) { const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt, att->TextureLevel); imageOffset += offsets[att->Zoffset]; } /* store that offset in the region */ intel_image->mt->region->draw_offset = imageOffset; /* update drawing region, etc */ intel_draw_buffer(ctx, fb); }