static void i915_miptree_layout_2d(struct intel_mipmap_tree * mt) { GLuint width = mt->width0; GLuint height = mt->height0; GLuint img_height; GLint level; mt->total_width = mt->width0; mt->total_height = 0; for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_level_info(mt, level, 0, mt->total_height, width, height, 1); if (mt->compressed) img_height = ALIGN(height, 4) / 4; else img_height = ALIGN(height, 2); mt->total_height += img_height; width = minify(width); height = minify(height); } }
static void apply_gen6_stencil_hiz_offset(struct isl_surf *surf, struct intel_mipmap_tree *mt, uint32_t lod, uint32_t *offset) { assert(mt->array_layout == ALL_SLICES_AT_EACH_LOD); if (mt->format == MESA_FORMAT_S_UINT8) { /* Note: we can't compute the stencil offset using * intel_miptree_get_aligned_offset(), because the miptree * claims that the region is untiled even though it's W tiled. */ *offset = mt->level[lod].level_y * mt->pitch + mt->level[lod].level_x * 64; } else { *offset = intel_miptree_get_aligned_offset(mt, mt->level[lod].level_x, mt->level[lod].level_y); } surf->logical_level0_px.width = minify(surf->logical_level0_px.width, lod); surf->logical_level0_px.height = minify(surf->logical_level0_px.height, lod); surf->phys_level0_sa.width = minify(surf->phys_level0_sa.width, lod); surf->phys_level0_sa.height = minify(surf->phys_level0_sa.height, lod); surf->levels = 1; surf->array_pitch_el_rows = ALIGN(surf->phys_level0_sa.height, surf->image_alignment_el.height); }
static void i915_miptree_layout_2d(struct intel_context *intel, struct intel_mipmap_tree * mt, uint32_t tiling) { GLuint width = mt->width0; GLuint height = mt->height0; GLuint img_height; GLint level; mt->pitch = intel_miptree_pitch_align (intel, mt, tiling, mt->width0); mt->total_height = 0; for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_level_info(mt, level, 1, 0, mt->total_height, width, height, 1); if (mt->compressed) img_height = MAX2(1, height / 4); else img_height = (MAX2(2, height) + 1) & ~1; mt->total_height += img_height; width = minify(width); height = minify(height); } }
static void r300_setup_miptree(struct r300_texture* tex) { struct pipe_texture* base = &tex->tex; int stride, size, offset; int i; for (i = 0; i <= base->last_level; i++) { if (i > 0) { base->width[i] = minify(base->width[i-1]); base->height[i] = minify(base->height[i-1]); base->depth[i] = minify(base->depth[i-1]); } base->nblocksx[i] = pf_get_nblocksx(&base->block, base->width[i]); base->nblocksy[i] = pf_get_nblocksy(&base->block, base->width[i]); /* Radeons enjoy things in multiples of 32. */ /* XXX this can be 32 when POT */ stride = (base->nblocksx[i] * base->block.size + 63) & ~63; size = stride * base->nblocksy[i] * base->depth[i]; tex->offset[i] = (tex->size + 63) & ~63; tex->size = tex->offset[i] + size; if (i == 0) { tex->stride = stride; } } }
static void calculate_miptree_layout(radeonContextPtr rmesa, radeon_mipmap_tree *mt) { GLuint curOffset, i, face, level; assert(mt->numLevels <= rmesa->glCtx.Const.MaxTextureLevels); curOffset = 0; for(face = 0; face < mt->faces; face++) { for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { mt->levels[level].valid = 1; mt->levels[level].width = minify(mt->width0, i); mt->levels[level].height = minify(mt->height0, i); mt->levels[level].depth = minify(mt->depth0, i); compute_tex_image_offset(rmesa, mt, face, level, &curOffset); } } /* Note the required size in memory */ mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; radeon_print(RADEON_TEXTURE, RADEON_TRACE, "%s(%p, %p) total size %d\n", __func__, rmesa, mt, mt->totalsize); }
void get_record_statistics(Record_Statistics *stats_out, Time_Record *records, int count){ Record_Statistics stats; stats.max = records[0]; stats.min = records[0]; stats.expected = records[0]; stats.count = count; Time_Record *record = records + 1; for (int i = 1; i < count; ++i, ++record){ stats.expected = stats.expected + *record; minify(stats.min.buffer, record->buffer); minify(stats.min.gap_buffer, record->gap_buffer); minify(stats.min.multi_gap_buffer, record->multi_gap_buffer); minify(stats.min.rope_buffer, record->rope_buffer); maxify(stats.max.buffer, record->buffer); maxify(stats.max.gap_buffer, record->gap_buffer); maxify(stats.max.multi_gap_buffer, record->multi_gap_buffer); maxify(stats.max.rope_buffer, record->rope_buffer); } stats.expected /= count; *stats_out = stats; }
static void brw_miptree_layout_texture_array(struct intel_context *intel, struct intel_mipmap_tree *mt) { GLuint level; GLuint qpitch = 0; int h0, h1, q; h0 = ALIGN(mt->height0, mt->align_h); h1 = ALIGN(minify(mt->height0), mt->align_h); if (mt->array_spacing_lod0) qpitch = h0; else qpitch = (h0 + h1 + (intel->gen >= 7 ? 12 : 11) * mt->align_h); if (mt->compressed) qpitch /= 4; i945_miptree_layout_2d(mt); for (level = mt->first_level; level <= mt->last_level; level++) { for (q = 0; q < mt->depth0; q++) { intel_miptree_set_image_offset(mt, level, q, 0, q * qpitch); } } mt->total_height = qpitch * mt->depth0; }
static void gen9_miptree_layout_1d(struct intel_mipmap_tree *mt) { unsigned x = 0; unsigned width = mt->physical_width0; unsigned depth = mt->physical_depth0; /* number of array layers. */ /* When this layout is used the horizontal alignment is fixed at 64 and the * hardware ignores the value given in the surface state */ const unsigned int align_w = 64; mt->total_height = mt->physical_height0; mt->total_width = 0; for (unsigned level = mt->first_level; level <= mt->last_level; level++) { unsigned img_width; intel_miptree_set_level_info(mt, level, x, 0, depth); img_width = ALIGN(width, align_w); mt->total_width = MAX2(mt->total_width, x + img_width); x += img_width; width = minify(width, 1); } }
//============================================================== void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe) { Tinstance *in; in=(Tinstance*)instance; ExceptionInfo *exception; /* Generamos la excepción */ exception = AcquireExceptionInfo(); /* Transformamos el mapa de imagen de entrada para imagemagick */ Image *im = ConstituteImage(in->size.width, in->size.height, "RGBA", CharPixel, inframe, exception); if (in->preview) { minify(&im, (int)in->preview, exception); } /* Generamos la imagen de salida */ Image *out = MotionBlurImage(im, in->radius, in->deviation, in->angle, exception); if (in->preview) { magnify(&out, (int)in->preview, exception); } /* Volvemos a coger el contenido de la imagen para frei0r */ ExportImagePixels(out, 0, 0, in->size.width, in->size.height, "RGBA", CharPixel, outframe, exception); /* Liberamos memoria */ exception = DestroyExceptionInfo(exception); im = DestroyImage(im); out = DestroyImage(out); }
static void brw_miptree_layout_texture_array(struct brw_context *brw, struct intel_mipmap_tree *mt) { unsigned qpitch = 0; int h0, h1; h0 = ALIGN(mt->physical_height0, mt->align_h); h1 = ALIGN(minify(mt->physical_height0, 1), mt->align_h); if (mt->array_spacing_lod0) qpitch = h0; else qpitch = (h0 + h1 + (brw->gen >= 7 ? 12 : 11) * mt->align_h); if (mt->compressed) qpitch /= 4; brw_miptree_layout_2d(mt); for (unsigned level = mt->first_level; level <= mt->last_level; level++) { for (int q = 0; q < mt->physical_depth0; q++) { intel_miptree_set_image_offset(mt, level, q, 0, q * qpitch); } } mt->total_height = qpitch * mt->physical_depth0; align_cube(mt); }
static void i915_miptree_layout_3d(struct intel_context *intel, struct intel_mipmap_tree * mt, uint32_t tiling) { GLuint width = mt->width0; GLuint height = mt->height0; GLuint depth = mt->depth0; GLuint stack_height = 0; GLint level; /* Calculate the size of a single slice. */ mt->pitch = intel_miptree_pitch_align (intel, mt, tiling, mt->width0); /* XXX: hardware expects/requires 9 levels at minimum. */ for (level = mt->first_level; level <= MAX2(8, mt->last_level); level++) { intel_miptree_set_level_info(mt, level, depth, 0, mt->total_height, width, height, depth); stack_height += MAX2(2, height); width = minify(width); height = minify(height); depth = minify(depth); } /* Fixup depth image_offsets: */ depth = mt->depth0; for (level = mt->first_level; level <= mt->last_level; level++) { GLuint i; for (i = 0; i < depth; i++) { intel_miptree_set_image_offset(mt, level, i, 0, i * stack_height); } depth = minify(depth); } /* Multiply slice size by texture depth for total size. It's * remarkable how wasteful of memory the i915 texture layouts * are. They are largely fixed in the i945. */ mt->total_height = stack_height * mt->depth0; }
unsigned brw_miptree_get_vertical_slice_pitch(const struct brw_context *brw, const struct intel_mipmap_tree *mt, unsigned level) { if (brw->gen >= 9) { /* ALL_SLICES_AT_EACH_LOD isn't supported on Gen8+ but this code will * effectively end up with a packed qpitch anyway whenever * mt->first_level == mt->last_level. */ assert(mt->array_layout != ALL_SLICES_AT_EACH_LOD); /* On Gen9 we can pick whatever qpitch we like as long as it's aligned * to the vertical alignment so we don't need to add any extra rows. */ unsigned qpitch = mt->total_height; /* If the surface might be used as a stencil buffer or HiZ buffer then * it needs to be a multiple of 8. */ const GLenum base_format = _mesa_get_format_base_format(mt->format); if (_mesa_is_depth_or_stencil_format(base_format)) qpitch = ALIGN(qpitch, 8); /* 3D textures need to be aligned to the tile height. At this point we * don't know which tiling will be used so let's just align it to 32 */ if (mt->target == GL_TEXTURE_3D) qpitch = ALIGN(qpitch, 32); return qpitch; } else if (mt->target == GL_TEXTURE_3D || (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP) || mt->array_layout == ALL_SLICES_AT_EACH_LOD) { return ALIGN_NPOT(minify(mt->physical_height0, level), mt->align_h); } else { const unsigned h0 = ALIGN_NPOT(mt->physical_height0, mt->align_h); const unsigned h1 = ALIGN_NPOT(minify(mt->physical_height0, 1), mt->align_h); return h0 + h1 + (brw->gen >= 7 ? 12 : 11) * mt->align_h; } }
static void brw_miptree_layout_texture_array(struct brw_context *brw, struct intel_mipmap_tree *mt) { int h0, h1; unsigned height = mt->physical_height0; bool layout_1d = use_linear_1d_layout(brw, mt); h0 = ALIGN(mt->physical_height0, mt->align_h); h1 = ALIGN(minify(mt->physical_height0, 1), mt->align_h); if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) mt->qpitch = h0; else mt->qpitch = (h0 + h1 + (brw->gen >= 7 ? 12 : 11) * mt->align_h); int physical_qpitch = mt->compressed ? mt->qpitch / 4 : mt->qpitch; if (layout_1d) gen9_miptree_layout_1d(mt); else brw_miptree_layout_2d(mt); for (unsigned level = mt->first_level; level <= mt->last_level; level++) { unsigned img_height; img_height = ALIGN(height, mt->align_h); if (mt->compressed) img_height /= mt->align_h; for (int q = 0; q < mt->level[level].depth; q++) { if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) { intel_miptree_set_image_offset(mt, level, q, 0, q * img_height); } else { intel_miptree_set_image_offset(mt, level, q, 0, q * physical_qpitch); } } height = minify(height, 1); } if (mt->array_layout == ALL_LOD_IN_EACH_SLICE) mt->total_height = physical_qpitch * mt->physical_depth0; align_cube(mt); }
unsigned brw_miptree_get_horizontal_slice_pitch(const struct brw_context *brw, const struct intel_mipmap_tree *mt, unsigned level) { if ((brw->gen < 9 && mt->target == GL_TEXTURE_3D) || (brw->gen == 4 && mt->target == GL_TEXTURE_CUBE_MAP)) { return ALIGN_NPOT(minify(mt->physical_width0, level), mt->align_w); } else { return 0; } }
/** * Sets up a DRIImage structure to point to a slice out of a miptree. */ static void intel_setup_image_from_mipmap_tree(struct brw_context *brw, __DRIimage *image, struct intel_mipmap_tree *mt, GLuint level, GLuint zoffset) { intel_miptree_make_shareable(brw, mt); intel_miptree_check_level_layer(mt, level, zoffset); image->width = minify(mt->physical_width0, level - mt->first_level); image->height = minify(mt->physical_height0, level - mt->first_level); image->pitch = mt->pitch; image->offset = intel_miptree_get_tile_offsets(mt, level, zoffset, &image->tile_x, &image->tile_y); drm_intel_bo_unreference(image->bo); image->bo = mt->bo; drm_intel_bo_reference(mt->bo); }
/* Conventional allocation path for non-display textures: */ static boolean softpipe_texture_layout(struct pipe_screen *screen, struct softpipe_texture * spt) { struct pipe_winsys *ws = screen->winsys; struct pipe_texture *pt = &spt->base; unsigned level; unsigned width = pt->width[0]; unsigned height = pt->height[0]; unsigned depth = pt->depth[0]; unsigned buffer_size = 0; for (level = 0; level <= pt->last_level; level++) { pt->width[level] = width; pt->height[level] = height; pt->depth[level] = depth; pt->nblocksx[level] = pf_get_nblocksx(&pt->block, width); pt->nblocksy[level] = pf_get_nblocksy(&pt->block, height); spt->stride[level] = pt->nblocksx[level]*pt->block.size; spt->level_offset[level] = buffer_size; buffer_size += (pt->nblocksy[level] * ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * spt->stride[level]); width = minify(width); height = minify(height); depth = minify(depth); } spt->buffer = ws->buffer_create(ws, 32, PIPE_BUFFER_USAGE_PIXEL, buffer_size); return spt->buffer != NULL; }
void brw_blorp_mip_info::set(struct intel_mipmap_tree *mt, unsigned int level, unsigned int layer) { /* Layer is a physical layer, so if this is a 2D multisample array texture * using INTEL_MSAA_LAYOUT_UMS or INTEL_MSAA_LAYOUT_CMS, then it had better * be a multiple of num_samples. */ if (mt->msaa_layout == INTEL_MSAA_LAYOUT_UMS || mt->msaa_layout == INTEL_MSAA_LAYOUT_CMS) { assert(layer % mt->num_samples == 0); } intel_miptree_check_level_layer(mt, level, layer); this->mt = mt; this->level = level; this->layer = layer; this->width = minify(mt->physical_width0, level - mt->first_level); this->height = minify(mt->physical_height0, level - mt->first_level); intel_miptree_get_image_offset(mt, level, layer, &x_offset, &y_offset); }
static void brw_miptree_layout_texture_array(struct brw_context *brw, struct intel_mipmap_tree *mt) { unsigned height = mt->physical_height0; bool layout_1d = gen9_use_linear_1d_layout(brw, mt); int physical_qpitch; if (layout_1d) gen9_miptree_layout_1d(mt); else brw_miptree_layout_2d(mt); if (layout_1d) { physical_qpitch = 1; /* When using the horizontal layout the qpitch specifies the distance in * pixels between array slices. The total_width is forced to be a * multiple of the horizontal alignment in brw_miptree_layout_1d (in * this case it's always 64). The vertical alignment is ignored. */ mt->qpitch = mt->total_width; } else { mt->qpitch = brw_miptree_get_vertical_slice_pitch(brw, mt, 0); /* Unlike previous generations the qpitch is a multiple of the * compressed block size on Gen9 so physical_qpitch matches mt->qpitch. */ physical_qpitch = (mt->compressed && brw->gen < 9 ? mt->qpitch / 4 : mt->qpitch); } for (unsigned level = mt->first_level; level <= mt->last_level; level++) { unsigned img_height; img_height = ALIGN_NPOT(height, mt->align_h); if (mt->compressed) img_height /= mt->align_h; for (unsigned q = 0; q < mt->level[level].depth; q++) { if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) { intel_miptree_set_image_offset(mt, level, q, 0, q * img_height); } else { intel_miptree_set_image_offset(mt, level, q, 0, q * physical_qpitch); } } height = minify(height, 1); } if (mt->array_layout == ALL_LOD_IN_EACH_SLICE) mt->total_height = physical_qpitch * mt->physical_depth0; align_cube(mt); }
void ofxUISuperCanvas::setMinified(bool _bIsMinified) { if(bIsMinified != _bIsMinified) { bIsMinified = _bIsMinified; if(bIsMinified) { minify(); } else { maximize(); } } }
float4 __CGsampler1DARRAY_state::sample(float4 strq, float lod) { lod += clampedLodBias; if (lod < minLod) { lod = minLod; } else if (lod > maxLod) { lod = maxLod; } else { // lod not clamped. } if (lod <= magnifyTransition) { return magnify(0, strq); } else { return minify(0, strq, lod); } }
/** * Implements fast depth clears on gen6+. * * Fast clears basically work by setting a flag in each of the subspans * represented in the HiZ buffer that says "When you need the depth values for * this subspan, it's the hardware's current clear value." Then later rendering * can just use the static clear value instead of referencing memory. * * The tricky part of the implementation is that you have to have the clear * value that was used on the depth buffer in place for all further rendering, * at least until a resolve to the real depth buffer happens. */ static bool brw_fast_clear_depth(struct gl_context *ctx) { struct brw_context *brw = brw_context(ctx); struct gl_framebuffer *fb = ctx->DrawBuffer; struct intel_renderbuffer *depth_irb = intel_get_renderbuffer(fb, BUFFER_DEPTH); struct intel_mipmap_tree *mt = depth_irb->mt; struct gl_renderbuffer_attachment *depth_att = &fb->Attachment[BUFFER_DEPTH]; if (brw->gen < 6) return false; if (!intel_renderbuffer_has_hiz(depth_irb)) return false; /* We only handle full buffer clears -- otherwise you'd have to track whether * a previous clear had happened at a different clear value and resolve it * first. */ if ((ctx->Scissor.EnableFlags & 1) && !noop_scissor(ctx, fb)) { perf_debug("Failed to fast clear %dx%d depth because of scissors. " "Possible 5%% performance win if avoided.\n", mt->logical_width0, mt->logical_height0); return false; } uint32_t depth_clear_value; switch (mt->format) { case MESA_FORMAT_Z32_FLOAT_S8X24_UINT: case MESA_FORMAT_Z24_UNORM_S8_UINT: /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be * enabled (the legacy method of clearing must be performed): * * - If the depth buffer format is D32_FLOAT_S8X24_UINT or * D24_UNORM_S8_UINT. */ return false; case MESA_FORMAT_Z_FLOAT32: depth_clear_value = float_as_int(ctx->Depth.Clear); break; case MESA_FORMAT_Z_UNORM16: /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "[DevSNB+]: Several cases exist where Depth Buffer Clear cannot be * enabled (the legacy method of clearing must be performed): * * - DevSNB{W/A}]: When depth buffer format is D16_UNORM and the * width of the map (LOD0) is not multiple of 16, fast clear * optimization must be disabled. */ if (brw->gen == 6 && (minify(mt->physical_width0, depth_irb->mt_level - mt->first_level) % 16) != 0) return false; /* FALLTHROUGH */ default: if (brw->gen >= 8) depth_clear_value = float_as_int(ctx->Depth.Clear); else depth_clear_value = fb->_DepthMax * ctx->Depth.Clear; break; } /* If we're clearing to a new clear value, then we need to resolve any clear * flags out of the HiZ buffer into the real depth buffer. */ if (mt->depth_clear_value != depth_clear_value) { intel_miptree_all_slices_resolve_depth(brw, mt); mt->depth_clear_value = depth_clear_value; } /* From the Sandy Bridge PRM, volume 2 part 1, page 313: * * "If other rendering operations have preceded this clear, a * PIPE_CONTROL with write cache flush enabled and Z-inhibit disabled * must be issued before the rectangle primitive used for the depth * buffer clear operation. */ brw_emit_mi_flush(brw); if (fb->MaxNumLayers > 0) { for (unsigned layer = 0; layer < depth_irb->layer_count; layer++) { intel_hiz_exec(brw, mt, depth_irb->mt_level, depth_irb->mt_layer + layer, GEN6_HIZ_OP_DEPTH_CLEAR); } } else { intel_hiz_exec(brw, mt, depth_irb->mt_level, depth_irb->mt_layer, GEN6_HIZ_OP_DEPTH_CLEAR); } if (brw->gen == 6) { /* From the Sandy Bridge PRM, volume 2 part 1, page 314: * * "DevSNB, DevSNB-B{W/A}]: Depth buffer clear pass must be followed * by a PIPE_CONTROL command with DEPTH_STALL bit set and Then * followed by Depth FLUSH' */ brw_emit_mi_flush(brw); } /* Now, the HiZ buffer contains data that needs to be resolved to the depth * buffer. */ intel_renderbuffer_att_set_needs_depth_resolve(depth_att); return true; }
/** * Called via ctx->Driver.GenerateMipmap() * Note: We don't yet support 3D textures, 1D/2D array textures or texture * borders. */ void _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *texObj) { struct gen_mipmap_state *mipmap = &ctx->Meta->Mipmap; struct vertex verts[4]; const GLuint baseLevel = texObj->BaseLevel; const GLuint maxLevel = texObj->MaxLevel; const GLint maxLevelSave = texObj->MaxLevel; const GLboolean genMipmapSave = texObj->GenerateMipmap; const GLuint currentTexUnitSave = ctx->Texture.CurrentUnit; const GLboolean use_glsl_version = ctx->Extensions.ARB_vertex_shader && ctx->Extensions.ARB_fragment_shader; GLenum faceTarget; GLuint dstLevel; GLuint samplerSave; GLint swizzle[4]; GLboolean swizzleSaved = GL_FALSE; if (fallback_required(ctx, target, texObj)) { _mesa_generate_mipmap(ctx, target, texObj); return; } if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) { faceTarget = target; target = GL_TEXTURE_CUBE_MAP; } else { faceTarget = target; } _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS); /* Choose between glsl version and fixed function version of * GenerateMipmap function. */ if (use_glsl_version) { _mesa_meta_setup_vertex_objects(&mipmap->VAO, &mipmap->VBO, true, 2, 4, 0); _mesa_meta_setup_blit_shader(ctx, target, false, &mipmap->shaders); } else { _mesa_meta_setup_ff_tnl_for_blit(&mipmap->VAO, &mipmap->VBO, 3); _mesa_set_enable(ctx, target, GL_TRUE); } samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ? ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0; if (currentTexUnitSave != 0) glBindTexture(target, texObj->Name); if (!mipmap->Sampler) { glGenSamplers(1, &mipmap->Sampler); glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); /* We don't want to encode or decode sRGB values; treat them as linear. * This is not technically correct for GLES3 but we don't get any API * error at the moment. */ if (ctx->Extensions.EXT_texture_sRGB_decode) { glSamplerParameteri(mipmap->Sampler, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT); } } else { glBindSampler(ctx->Texture.CurrentUnit, mipmap->Sampler); } assert(mipmap->FBO != 0); glBindFramebuffer(GL_FRAMEBUFFER, mipmap->FBO); glTexParameteri(target, GL_GENERATE_MIPMAP, GL_FALSE); // if (texObj->_Swizzle != SWIZZLE_NOOP) { // static const GLint swizzleNoop[4] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA }; // memcpy(swizzle, texObj->Swizzle, sizeof(swizzle)); // swizzleSaved = GL_TRUE; // glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzleNoop); // } /* Silence valgrind warnings about reading uninitialized stack. */ memset(verts, 0, sizeof(verts)); /* setup vertex positions */ verts[0].x = -1.0F; verts[0].y = -1.0F; verts[1].x = 1.0F; verts[1].y = -1.0F; verts[2].x = 1.0F; verts[2].y = 1.0F; verts[3].x = -1.0F; verts[3].y = 1.0F; /* texture is already locked, unlock now */ _mesa_unlock_texture(ctx, texObj); for (dstLevel = baseLevel + 1; dstLevel <= maxLevel; dstLevel++) { const struct gl_texture_image *srcImage; struct gl_texture_image *dstImage; const GLuint srcLevel = dstLevel - 1; GLuint layer; GLsizei srcWidth, srcHeight, srcDepth; GLsizei dstWidth, dstHeight, dstDepth; srcImage = _mesa_select_tex_image(texObj, faceTarget, srcLevel); assert(srcImage->Border == 0); /* src size */ srcWidth = srcImage->Width; if (target == GL_TEXTURE_1D_ARRAY) { srcHeight = 1; srcDepth = srcImage->Height; } else { srcHeight = srcImage->Height; srcDepth = srcImage->Depth; } /* new dst size */ dstWidth = minify(srcWidth, 1); dstHeight = minify(srcHeight, 1); // dstDepth = target == GL_TEXTURE_3D ? minify(srcDepth, 1) : srcDepth; dstDepth = srcDepth; if (dstWidth == srcWidth && dstHeight == srcHeight && dstDepth == srcDepth) { /* all done */ break; } /* Allocate storage for the destination mipmap image(s) */ /* Set MaxLevel large enough to hold the new level when we allocate it */ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, dstLevel); if (!prepare_mipmap_level(ctx, texObj, dstLevel, dstWidth, dstHeight, dstDepth, srcImage->InternalFormat, srcImage->TexFormat)) { /* All done. We either ran out of memory or we would go beyond the * last valid level of an immutable texture if we continued. */ break; } dstImage = _mesa_select_tex_image(texObj, faceTarget, dstLevel); /* limit minification to src level */ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, srcLevel); /* setup viewport */ _mesa_set_viewport(ctx, 0, 0, 0, dstWidth, dstHeight); glDrawBuffer(GL_COLOR_ATTACHMENT0); for (layer = 0; layer < dstDepth; ++layer) { /* Setup texture coordinates */ _mesa_meta_setup_texture_coords(faceTarget, layer, 0, 0, 1, /* width, height never used here */ verts[0].tex, verts[1].tex, verts[2].tex, verts[3].tex); /* upload vertex data */ glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_DYNAMIC_DRAW); _mesa_meta_bind_fbo_image(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dstImage, layer); /* sanity check */ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { _mesa_problem(ctx, "Unexpected incomplete framebuffer in " "_mesa_meta_GenerateMipmap()"); break; } assert(dstWidth == ctx->DrawBuffer->Width); if (target == GL_TEXTURE_1D_ARRAY) { assert(dstHeight == 1); } else { assert(dstHeight == ctx->DrawBuffer->Height); } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } } _mesa_lock_texture(ctx, texObj); /* relock */ glBindSampler(ctx->Texture.CurrentUnit, samplerSave); _mesa_meta_end(ctx); glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, maxLevelSave); if (genMipmapSave) glTexParameteri(target, GL_GENERATE_MIPMAP, genMipmapSave); // if (swizzleSaved) // glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle); }
void brw_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree *mt) { switch (mt->target) { case GL_TEXTURE_CUBE_MAP_ARRAY: brw_miptree_layout_texture_array(intel, mt); break; case GL_TEXTURE_CUBE_MAP: if (intel->gen >= 5) { /* On Ironlake, cube maps are finally represented as just a series of * MIPLAYOUT_BELOW 2D textures (like 2D texture arrays), separated by a * pitch of qpitch rows, where qpitch is defined by the equation given * in Volume 1 of the BSpec. */ brw_miptree_layout_texture_array(intel, mt); break; } assert(mt->physical_depth0 == 6); /* FALLTHROUGH */ case GL_TEXTURE_3D: { GLuint width = mt->physical_width0; GLuint height = mt->physical_height0; GLuint depth = mt->physical_depth0; GLuint pack_x_pitch, pack_x_nr; GLuint pack_y_pitch; GLuint level; mt->total_height = 0; if (mt->compressed) { mt->total_width = ALIGN(width, mt->align_w); pack_y_pitch = (height + 3) / 4; } else { mt->total_width = mt->physical_width0; pack_y_pitch = ALIGN(mt->physical_height0, mt->align_h); } pack_x_pitch = width; pack_x_nr = 1; for (level = mt->first_level ; level <= mt->last_level ; level++) { GLint x = 0; GLint y = 0; GLint q, j; intel_miptree_set_level_info(mt, level, 0, mt->total_height, width, height, depth); for (q = 0; q < depth; /* empty */) { for (j = 0; j < pack_x_nr && q < depth; j++, q++) { intel_miptree_set_image_offset(mt, level, q, x, y); x += pack_x_pitch; } if (x > mt->total_width) mt->total_width = x; x = 0; y += pack_y_pitch; } mt->total_height += y; width = minify(width); height = minify(height); if (mt->target == GL_TEXTURE_3D) depth = minify(depth); if (mt->compressed) { pack_y_pitch = (height + 3) / 4; if (pack_x_pitch > ALIGN(width, mt->align_w)) { pack_x_pitch = ALIGN(width, mt->align_w); pack_x_nr <<= 1; } } else { pack_x_nr <<= 1; if (pack_x_pitch > 4) { pack_x_pitch >>= 1; } if (pack_y_pitch > 2) { pack_y_pitch >>= 1; pack_y_pitch = ALIGN(pack_y_pitch, mt->align_h); } } } /* The 965's sampler lays cachelines out according to how accesses * in the texture surfaces run, so they may be "vertical" through * memory. As a result, the docs say in Surface Padding Requirements: * Sampling Engine Surfaces that two extra rows of padding are required. */ if (mt->target == GL_TEXTURE_CUBE_MAP) mt->total_height += 2; break; }
y += pack_y_pitch; } mt->total_height += y; if (pack_x_pitch > 4) { pack_x_pitch >>= 1; pack_x_nr <<= 1; assert(pack_x_pitch * pack_x_nr <= mt->total_width); } if (pack_y_pitch > 2) { pack_y_pitch >>= 1; } width = minify(width); height = minify(height); depth = minify(depth); } } void i945_miptree_layout(struct intel_mipmap_tree * mt) { switch (mt->target) { case GL_TEXTURE_CUBE_MAP: if (mt->compressed) i945_miptree_layout_cube(mt); else i915_miptree_layout_cube(mt); break;
static void brw_miptree_layout_2d(struct intel_mipmap_tree *mt) { unsigned x = 0; unsigned y = 0; unsigned width = mt->physical_width0; unsigned height = mt->physical_height0; unsigned depth = mt->physical_depth0; /* number of array layers. */ mt->total_width = mt->physical_width0; if (mt->compressed) { mt->total_width = ALIGN(mt->physical_width0, mt->align_w); } /* May need to adjust width to accomodate the placement of * the 2nd mipmap. This occurs when the alignment * constraints of mipmap placement push the right edge of the * 2nd mipmap out past the width of its parent. */ if (mt->first_level != mt->last_level) { unsigned mip1_width; if (mt->compressed) { mip1_width = ALIGN(minify(mt->physical_width0, 1), mt->align_w) + ALIGN(minify(mt->physical_width0, 2), mt->align_w); } else { mip1_width = ALIGN(minify(mt->physical_width0, 1), mt->align_w) + minify(mt->physical_width0, 2); } if (mip1_width > mt->total_width) { mt->total_width = mip1_width; } } mt->total_height = 0; for (unsigned level = mt->first_level; level <= mt->last_level; level++) { unsigned img_height; intel_miptree_set_level_info(mt, level, x, y, width, height, depth); img_height = ALIGN(height, mt->align_h); if (mt->compressed) img_height /= mt->align_h; /* Because the images are packed better, the final offset * might not be the maximal one: */ mt->total_height = MAX2(mt->total_height, y + img_height); /* Layout_below: step right after second mipmap. */ if (level == mt->first_level + 1) { x += ALIGN(width, mt->align_w); } else { y += img_height; } width = minify(width, 1); height = minify(height, 1); } }
GLboolean brw_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree *mt, uint32_t tiling) { /* XXX: these vary depending on image format: */ /* GLint align_w = 4; */ switch (mt->target) { case GL_TEXTURE_CUBE_MAP: if (intel->gen == 5) { GLuint align_h = 2; GLuint level; GLuint qpitch = 0; int h0, h1, q; /* On Ironlake, cube maps are finally represented as just a series * of MIPLAYOUT_BELOW 2D textures (like 2D texture arrays), separated * by a pitch of qpitch rows, where qpitch is defined by the equation * given in Volume 1 of the BSpec. */ h0 = ALIGN(mt->height0, align_h); h1 = ALIGN(minify(h0), align_h); qpitch = (h0 + h1 + 11 * align_h); if (mt->compressed) qpitch /= 4; i945_miptree_layout_2d(intel, mt, tiling, 6); for (level = mt->first_level; level <= mt->last_level; level++) { for (q = 0; q < 6; q++) { intel_miptree_set_image_offset(mt, level, q, 0, q * qpitch); } } mt->total_height = qpitch * 6; break; } case GL_TEXTURE_3D: { GLuint width = mt->width0; GLuint height = mt->height0; GLuint depth = mt->depth0; GLuint pack_x_pitch, pack_x_nr; GLuint pack_y_pitch; GLuint level; GLuint align_h = 2; GLuint align_w = 4; mt->total_height = 0; intel_get_texture_alignment_unit(mt->internal_format, &align_w, &align_h); if (mt->compressed) { mt->pitch = ALIGN(width, align_w); pack_y_pitch = (height + 3) / 4; } else { mt->pitch = intel_miptree_pitch_align (intel, mt, tiling, mt->width0); pack_y_pitch = ALIGN(mt->height0, align_h); } pack_x_pitch = width; pack_x_nr = 1; for (level = mt->first_level ; level <= mt->last_level ; level++) { GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6; GLint x = 0; GLint y = 0; GLint q, j; intel_miptree_set_level_info(mt, level, nr_images, 0, mt->total_height, width, height, depth); for (q = 0; q < nr_images;) { for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) { intel_miptree_set_image_offset(mt, level, q, x, y); x += pack_x_pitch; } x = 0; y += pack_y_pitch; } mt->total_height += y; width = minify(width); height = minify(height); depth = minify(depth); if (mt->compressed) { pack_y_pitch = (height + 3) / 4; if (pack_x_pitch > ALIGN(width, align_w)) { pack_x_pitch = ALIGN(width, align_w); pack_x_nr <<= 1; } } else { if (pack_x_pitch > 4) { pack_x_pitch >>= 1; pack_x_nr <<= 1; assert(pack_x_pitch * pack_x_nr <= mt->pitch); } if (pack_y_pitch > 2) { pack_y_pitch >>= 1; pack_y_pitch = ALIGN(pack_y_pitch, align_h); } } } /* The 965's sampler lays cachelines out according to how accesses * in the texture surfaces run, so they may be "vertical" through * memory. As a result, the docs say in Surface Padding Requirements: * Sampling Engine Surfaces that two extra rows of padding are required. * We don't know of similar requirements for pre-965, but given that * those docs are silent on padding requirements in general, let's play * it safe. */ if (mt->target == GL_TEXTURE_CUBE_MAP) mt->total_height += 2; break; }
GLboolean i915_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt) { GLint level; switch (mt->target) { case GL_TEXTURE_CUBE_MAP:{ const GLuint dim = mt->width0; GLuint face; GLuint lvlWidth = mt->width0, lvlHeight = mt->height0; assert(lvlWidth == lvlHeight); /* cubemap images are square */ /* double pitch for cube layouts */ mt->pitch = intel_miptree_pitch_align (intel, mt, dim * 2); mt->total_height = dim * 4; for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_level_info(mt, level, 6, 0, 0, /*OLD: mt->pitch, mt->total_height,*/ lvlWidth, lvlHeight, 1); lvlWidth /= 2; lvlHeight /= 2; } for (face = 0; face < 6; face++) { GLuint x = initial_offsets[face][0] * dim; GLuint y = initial_offsets[face][1] * dim; GLuint d = dim; for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_image_offset(mt, level, face, x, y); if (d == 0) _mesa_printf("cube mipmap %d/%d (%d..%d) is 0x0\n", face, level, mt->first_level, mt->last_level); d >>= 1; x += step_offsets[face][0] * d; y += step_offsets[face][1] * d; } } break; } case GL_TEXTURE_3D:{ GLuint width = mt->width0; GLuint height = mt->height0; GLuint depth = mt->depth0; GLuint stack_height = 0; /* Calculate the size of a single slice. */ mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0); /* XXX: hardware expects/requires 9 levels at minimum. */ for (level = mt->first_level; level <= MAX2(8, mt->last_level); level++) { intel_miptree_set_level_info(mt, level, depth, 0, mt->total_height, width, height, depth); stack_height += MAX2(2, height); width = minify(width); height = minify(height); depth = minify(depth); } /* Fixup depth image_offsets: */ depth = mt->depth0; for (level = mt->first_level; level <= mt->last_level; level++) { GLuint i; for (i = 0; i < depth; i++) intel_miptree_set_image_offset(mt, level, i, 0, i * stack_height); depth = minify(depth); } /* Multiply slice size by texture depth for total size. It's * remarkable how wasteful of memory the i915 texture layouts * are. They are largely fixed in the i945. */ mt->total_height = stack_height * mt->depth0; break; } default:{ GLuint width = mt->width0; GLuint height = mt->height0; GLuint img_height; mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0); mt->total_height = 0; for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_level_info(mt, level, 1, 0, mt->total_height, width, height, 1); if (mt->compressed) img_height = MAX2(1, height / 4); else img_height = (MAX2(2, height) + 1) & ~1; mt->total_height += img_height; width = minify(width); height = minify(height); } break; } } DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__, mt->pitch, mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp); return GL_TRUE; }
static void brw_miptree_layout_2d(struct intel_mipmap_tree *mt) { unsigned x = 0; unsigned y = 0; unsigned width = mt->physical_width0; unsigned height = mt->physical_height0; unsigned depth = mt->physical_depth0; /* number of array layers. */ unsigned int bw, bh; _mesa_get_format_block_size(mt->format, &bw, &bh); mt->total_width = mt->physical_width0; if (mt->compressed) mt->total_width = ALIGN_NPOT(mt->total_width, bw); /* May need to adjust width to accommodate the placement of * the 2nd mipmap. This occurs when the alignment * constraints of mipmap placement push the right edge of the * 2nd mipmap out past the width of its parent. */ if (mt->first_level != mt->last_level) { unsigned mip1_width; if (mt->compressed) { mip1_width = ALIGN_NPOT(minify(mt->physical_width0, 1), mt->align_w) + ALIGN_NPOT(minify(mt->physical_width0, 2), bw); } else { mip1_width = ALIGN_NPOT(minify(mt->physical_width0, 1), mt->align_w) + minify(mt->physical_width0, 2); } if (mip1_width > mt->total_width) { mt->total_width = mip1_width; } } mt->total_width /= bw; mt->total_height = 0; for (unsigned level = mt->first_level; level <= mt->last_level; level++) { unsigned img_height; intel_miptree_set_level_info(mt, level, x, y, depth); img_height = ALIGN_NPOT(height, mt->align_h); if (mt->compressed) img_height /= bh; if (mt->array_layout == ALL_SLICES_AT_EACH_LOD) { /* Compact arrays with separated miplevels */ img_height *= depth; } /* Because the images are packed better, the final offset * might not be the maximal one: */ mt->total_height = MAX2(mt->total_height, y + img_height); /* Layout_below: step right after second mipmap. */ if (level == mt->first_level + 1) { x += ALIGN_NPOT(width, mt->align_w) / bw; } else { y += img_height; } width = minify(width, 1); height = minify(height, 1); if (mt->target == GL_TEXTURE_3D) depth = minify(depth, 1); } }
/** * The GenerateMipmap() driver hook. */ void brw_generate_mipmap(struct gl_context *ctx, GLenum target, struct gl_texture_object *tex_obj) { struct brw_context *brw = brw_context(ctx); struct gen_device_info *devinfo = &brw->screen->devinfo; struct intel_texture_object *intel_obj = intel_texture_object(tex_obj); const unsigned base_level = tex_obj->BaseLevel; unsigned last_level, first_layer, last_layer; /* Blorp doesn't handle combined depth/stencil surfaces on Gen4-5 yet. */ if (devinfo->gen <= 5 && (tex_obj->Image[0][base_level]->_BaseFormat == GL_DEPTH_COMPONENT || tex_obj->Image[0][base_level]->_BaseFormat == GL_DEPTH_STENCIL)) { _mesa_meta_GenerateMipmap(ctx, target, tex_obj); return; } /* find expected last mipmap level to generate */ last_level = _mesa_compute_num_levels(ctx, tex_obj, target) - 1; if (last_level == 0) return; /* The texture isn't in a "complete" state yet so set the expected * last_level here; we're not going through normal texture validation. */ intel_obj->_MaxLevel = last_level; if (!tex_obj->Immutable) { _mesa_prepare_mipmap_levels(ctx, tex_obj, base_level, last_level); /* At this point, memory for all the texture levels has been * allocated. However, the base level image may be in one resource * while the subsequent/smaller levels may be in another resource. * Finalizing the texture will copy the base images from the former * resource to the latter. * * After this, we'll have all mipmap levels in one resource. */ intel_finalize_mipmap_tree(brw, tex_obj); } struct intel_mipmap_tree *mt = intel_obj->mt; if (!mt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "mipmap generation"); return; } const mesa_format format = intel_obj->_Format; /* Fall back to the CPU for non-renderable cases. * * TODO: 3D textures require blending data from multiple slices, * which means we need custom shaders. For now, fall back. */ if (!brw->mesa_format_supports_render[format] || target == GL_TEXTURE_3D) { _mesa_generate_mipmap(ctx, target, tex_obj); return; } const struct isl_extent4d *base_size = &mt->surf.logical_level0_px; if (mt->target == GL_TEXTURE_CUBE_MAP) { first_layer = _mesa_tex_target_to_face(target); last_layer = first_layer; } else { first_layer = 0; last_layer = base_size->array_len - 1; } /* The GL_EXT_texture_sRGB_decode extension's issues section says: * * "10) How is mipmap generation of sRGB textures affected by the * TEXTURE_SRGB_DECODE_EXT parameter? * * RESOLVED: When the TEXTURE_SRGB_DECODE parameter is DECODE_EXT * for an sRGB texture, mipmap generation should decode sRGB texels * to a linear RGB color space, perform downsampling, then encode * back to an sRGB color space. (Issue 24 in the EXT_texture_sRGB * specification provides a rationale for why.) When the parameter * is SKIP_DECODE_EXT instead, mipmap generation skips the encode * and decode steps during mipmap generation. By skipping the * encode and decode steps, sRGB mipmap generation should match * the mipmap generation for a non-sRGB texture." */ bool do_srgb = tex_obj->Sampler.sRGBDecode == GL_DECODE_EXT; for (unsigned dst_level = base_level + 1; dst_level <= last_level; dst_level++) { const unsigned src_level = dst_level - 1; for (unsigned layer = first_layer; layer <= last_layer; layer++) { brw_blorp_blit_miptrees(brw, mt, src_level, layer, format, SWIZZLE_XYZW, mt, dst_level, layer, format, 0, 0, minify(base_size->width, src_level), minify(base_size->height, src_level), 0, 0, minify(base_size->width, dst_level), minify(base_size->height, dst_level), GL_LINEAR, false, false, do_srgb, do_srgb); } } }
GLboolean i945_miptree_layout(struct intel_context *intel, struct intel_mipmap_tree * mt) { GLint level; switch (mt->target) { case GL_TEXTURE_CUBE_MAP:{ const GLuint dim = mt->width0; GLuint face; GLuint lvlWidth = mt->width0, lvlHeight = mt->height0; assert(lvlWidth == lvlHeight); /* cubemap images are square */ /* Depending on the size of the largest images, pitch can be * determined either by the old-style packing of cubemap faces, * or the final row of 4x4, 2x2 and 1x1 faces below this. */ if (dim > 32) mt->pitch = intel_miptree_pitch_align (intel, mt, dim); else mt->pitch = 14 * 8; mt->total_height = dim * 4 + 4; /* Set all the levels to effectively occupy the whole rectangular region. */ for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_level_info(mt, level, 6, 0, 0, lvlWidth, lvlHeight, 1); lvlWidth /= 2; lvlHeight /= 2; } for (face = 0; face < 6; face++) { GLuint x = initial_offsets[face][0] * dim; GLuint y = initial_offsets[face][1] * dim; GLuint d = dim; if (dim == 4 && face >= 4) { y = mt->total_height - 4; x = (face - 4) * 8; } else if (dim < 4 && (face > 0 || mt->first_level > 0)) { y = mt->total_height - 4; x = face * 8; } for (level = mt->first_level; level <= mt->last_level; level++) { intel_miptree_set_image_offset(mt, level, face, x, y); d >>= 1; switch (d) { case 4: switch (face) { case FACE_POS_X: case FACE_NEG_X: x += step_offsets[face][0] * d; y += step_offsets[face][1] * d; break; case FACE_POS_Y: case FACE_NEG_Y: y += 12; x -= 8; break; case FACE_POS_Z: case FACE_NEG_Z: y = mt->total_height - 4; x = (face - 4) * 8; break; } case 2: y = mt->total_height - 4; x = 16 + face * 8; break; case 1: x += 48; break; default: x += step_offsets[face][0] * d; y += step_offsets[face][1] * d; break; } } } break; } case GL_TEXTURE_3D:{ GLuint width = mt->width0; GLuint height = mt->height0; GLuint depth = mt->depth0; GLuint pack_x_pitch, pack_x_nr; GLuint pack_y_pitch; GLuint level; mt->pitch = intel_miptree_pitch_align (intel, mt, mt->width0); mt->total_height = 0; pack_y_pitch = MAX2(mt->height0, 2); pack_x_pitch = mt->pitch; pack_x_nr = 1; for (level = mt->first_level; level <= mt->last_level; level++) { GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6; GLint x = 0; GLint y = 0; GLint q, j; intel_miptree_set_level_info(mt, level, nr_images, 0, mt->total_height, width, height, depth); for (q = 0; q < nr_images;) { for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) { intel_miptree_set_image_offset(mt, level, q, x, y); x += pack_x_pitch; } x = 0; y += pack_y_pitch; } mt->total_height += y; if (pack_x_pitch > 4) { pack_x_pitch >>= 1; pack_x_nr <<= 1; assert(pack_x_pitch * pack_x_nr <= mt->pitch); } if (pack_y_pitch > 2) { pack_y_pitch >>= 1; } width = minify(width); height = minify(height); depth = minify(depth); } break; }