1f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/* 2f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright (C) 2009 Maciej Cencora. 3f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Copyright (C) 2008 Nicolai Haehnle. 4f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 5f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * All Rights Reserved. 6f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 7f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Permission is hereby granted, free of charge, to any person obtaining 8f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * a copy of this software and associated documentation files (the 9f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * "Software"), to deal in the Software without restriction, including 10f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * without limitation the rights to use, copy, modify, merge, publish, 11f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * distribute, sublicense, and/or sell copies of the Software, and to 12f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * permit persons to whom the Software is furnished to do so, subject to 13f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * the following conditions: 14f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 15f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * The above copyright notice and this permission notice (including the 16f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * next paragraph) shall be included in all copies or substantial 17f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * portions of the Software. 18f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 19f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 23f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 27f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 28f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 29f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "radeon_mipmap_tree.h" 30f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 31f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <errno.h> 32f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include <unistd.h> 33f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 34f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "main/simple_list.h" 35f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "main/teximage.h" 36f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "main/texobj.h" 37f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "main/enums.h" 38f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "radeon_texture.h" 39f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org#include "radeon_tile.h" 40f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 41f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic unsigned get_aligned_compressed_row_stride( 42f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org gl_format format, 43f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned width, 44f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned minStride) 45f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 46f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const unsigned blockBytes = _mesa_get_format_bytes(format); 47f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned blockWidth, blockHeight; 48f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned stride; 49f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 50f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org _mesa_get_format_block_size(format, &blockWidth, &blockHeight); 51f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 52f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Count number of blocks required to store the given width. 53f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * And then multiple it with bytes required to store a block. 54f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 55f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org stride = (width + blockWidth - 1) / blockWidth * blockBytes; 56f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 57f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Round the given minimum stride to the next full blocksize. 58f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * (minStride + blockBytes - 1) / blockBytes * blockBytes 59f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 60f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if ( stride < minStride ) 61f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org stride = (minStride + blockBytes - 1) / blockBytes * blockBytes; 62f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 63f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 64f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s width %u, minStride %u, block(bytes %u, width %u):" 65f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "stride %u\n", 66f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, width, minStride, 67f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org blockBytes, blockWidth, 68f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org stride); 69f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 70f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return stride; 71f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 72f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 73f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgunsigned get_texture_image_size( 74f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org gl_format format, 75f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned rowStride, 76f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned height, 77f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned depth, 78f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned tiling) 79f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 80f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (_mesa_is_format_compressed(format)) { 81f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned blockWidth, blockHeight; 82f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 83f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org _mesa_get_format_block_size(format, &blockWidth, &blockHeight); 84f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 85f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return rowStride * ((height + blockHeight - 1) / blockHeight) * depth; 86f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else if (tiling) { 87f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Need to align height to tile height */ 88f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned tileWidth, tileHeight; 89f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 90f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org get_tile_size(format, &tileWidth, &tileHeight); 91f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org tileHeight--; 92f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 93f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org height = (height + tileHeight) & ~tileHeight; 94f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 95f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 96f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return rowStride * height * depth; 97f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 98f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 99f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgunsigned get_texture_image_row_stride(radeonContextPtr rmesa, gl_format format, unsigned width, unsigned tiling, GLuint target) 100f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 101f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (_mesa_is_format_compressed(format)) { 102f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return get_aligned_compressed_row_stride(format, width, rmesa->texture_compressed_row_align); 103f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 104f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned row_align; 105f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 106f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!_mesa_is_pow_two(width) || target == GL_TEXTURE_RECTANGLE) { 107f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org row_align = rmesa->texture_rect_row_align - 1; 108f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else if (tiling) { 109f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned tileWidth, tileHeight; 110f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org get_tile_size(format, &tileWidth, &tileHeight); 111f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org row_align = tileWidth * _mesa_get_format_bytes(format) - 1; 112f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 113f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org row_align = rmesa->texture_row_align - 1; 114f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 115f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 116f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return (_mesa_format_row_stride(format, width) + row_align) & ~row_align; 117f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 118f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 119f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 120f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 121f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Compute sizes and fill in offset and blit information for the given 122f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * image (determined by \p face and \p level). 123f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * 124f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * \param curOffset points to the offset at which the image is to be stored 125f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * and is updated by this function according to the size of the image. 126f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 127f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void compute_tex_image_offset(radeonContextPtr rmesa, radeon_mipmap_tree *mt, 128f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint face, GLuint level, GLuint* curOffset) 129f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 130f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_level *lvl = &mt->levels[level]; 131f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint height; 132f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 133f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org height = _mesa_next_pow_two_32(lvl->height); 134f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 135f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->rowstride = get_texture_image_row_stride(rmesa, mt->mesaFormat, lvl->width, mt->tilebits, mt->target); 136f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->size = get_texture_image_size(mt->mesaFormat, lvl->rowstride, height, lvl->depth, mt->tilebits); 137f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 138f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(lvl->size > 0); 139f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 140f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->faces[face].offset = *curOffset; 141f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *curOffset += lvl->size; 142f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 143f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 144f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s(%p) level %d, face %d: rs:%d %dx%d at %d\n", 145f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, rmesa, 146f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org level, face, 147f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->rowstride, lvl->width, height, lvl->faces[face].offset); 148f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 149f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 150f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic GLuint minify(GLuint size, GLuint levels) 151f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 152f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org size = size >> levels; 153f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (size < 1) 154f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org size = 1; 155f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return size; 156f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 157f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 158f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 159f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void calculate_miptree_layout(radeonContextPtr rmesa, radeon_mipmap_tree *mt) 160f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 161f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint curOffset, i, face, level; 162f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 163f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(mt->numLevels <= rmesa->glCtx->Const.MaxTextureLevels); 164f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 165f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org curOffset = 0; 166f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for(face = 0; face < mt->faces; face++) { 167f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 168f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for(i = 0, level = mt->baseLevel; i < mt->numLevels; i++, level++) { 169f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->levels[level].valid = 1; 170f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->levels[level].width = minify(mt->width0, i); 171f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->levels[level].height = minify(mt->height0, i); 172f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->levels[level].depth = minify(mt->depth0, i); 173f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org compute_tex_image_offset(rmesa, mt, face, level, &curOffset); 174f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 175f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 176f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 177f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Note the required size in memory */ 178f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->totalsize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; 179f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 180f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 181f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s(%p, %p) total size %d\n", 182f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, rmesa, mt, mt->totalsize); 183f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 184f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 185f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 186f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Create a new mipmap tree, calculate its layout and allocate memory. 187f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 188f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgradeon_mipmap_tree* radeon_miptree_create(radeonContextPtr rmesa, 189f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLenum target, gl_format mesaFormat, GLuint baseLevel, GLuint numLevels, 190f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint width0, GLuint height0, GLuint depth0, GLuint tilebits) 191f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 192f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_tree *mt = CALLOC_STRUCT(_radeon_mipmap_tree); 193f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 194f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_NORMAL, 195f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s(%p) new tree is %p.\n", 196f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, rmesa, mt); 197f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 198f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->mesaFormat = mesaFormat; 199f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->refcount = 1; 200f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->target = target; 201f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->faces = _mesa_num_tex_faces(target); 202f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->baseLevel = baseLevel; 203f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->numLevels = numLevels; 204f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->width0 = width0; 205f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->height0 = height0; 206f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->depth0 = depth0; 207f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->tilebits = tilebits; 208f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 209f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org calculate_miptree_layout(rmesa, mt); 210f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 211f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->bo = radeon_bo_open(rmesa->radeonScreen->bom, 212f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 0, mt->totalsize, 1024, 213f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org RADEON_GEM_DOMAIN_VRAM, 214f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 0); 215f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 216f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return mt; 217f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 218f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 219f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid radeon_miptree_reference(radeon_mipmap_tree *mt, radeon_mipmap_tree **ptr) 220f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 221f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(!*ptr); 222f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 223f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->refcount++; 224f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(mt->refcount > 0); 225f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 226f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *ptr = mt; 227f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 228f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 229f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid radeon_miptree_unreference(radeon_mipmap_tree **ptr) 230f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 231f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_tree *mt = *ptr; 232f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!mt) 233f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return; 234f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 235f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(mt->refcount > 0); 236f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 237f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->refcount--; 238f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!mt->refcount) { 239f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_bo_unref(mt->bo); 240f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org free(mt); 241f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 242f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 243f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *ptr = 0; 244f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 245f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 246f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 247f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Calculate min and max LOD for the given texture object. 248f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] tObj texture object whose LOD values to calculate 249f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[out] pminLod minimal LOD 250f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[out] pmaxLod maximal LOD 251f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 252f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void calculate_min_max_lod(struct gl_sampler_object *samp, struct gl_texture_object *tObj, 253f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned *pminLod, unsigned *pmaxLod) 254f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 255f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int minLod, maxLod; 256f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Yes, this looks overly complicated, but it's all needed. 257f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 258f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org switch (tObj->Target) { 259f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_1D: 260f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_2D: 261f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_3D: 262f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_CUBE_MAP: 263f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) { 264f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. 265f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 266f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod = maxLod = tObj->BaseLevel; 267f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 268f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod = tObj->BaseLevel + (GLint)(samp->MinLod); 269f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod = MAX2(minLod, tObj->BaseLevel); 270f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod = MIN2(minLod, tObj->MaxLevel); 271f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org maxLod = tObj->BaseLevel + (GLint)(samp->MaxLod + 0.5); 272f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org maxLod = MIN2(maxLod, tObj->MaxLevel); 273f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org maxLod = MIN2(maxLod, tObj->Image[0][minLod]->MaxNumLevels - 1 + minLod); 274f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org maxLod = MAX2(maxLod, minLod); /* need at least one level */ 275f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 276f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org break; 277f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_RECTANGLE_NV: 278f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org case GL_TEXTURE_4D_SGIS: 279f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod = maxLod = 0; 280f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org break; 281f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org default: 282f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return; 283f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 284f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 285f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 286f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s(%p) target %s, min %d, max %d.\n", 287f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, tObj, 288f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org _mesa_lookup_enum_by_nr(tObj->Target), 289f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org minLod, maxLod); 290f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 291f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* save these values */ 292f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *pminLod = minLod; 293f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org *pmaxLod = maxLod; 294f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 295f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 296f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 297f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Checks whether the given miptree can hold the given texture image at the 298f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * given face and level. 299f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 300f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgGLboolean radeon_miptree_matches_image(radeon_mipmap_tree *mt, 301f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_texture_image *texImage) 302f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 303f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_level *lvl; 304f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint level = texImage->Level; 305f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (texImage->TexFormat != mt->mesaFormat) 306f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_FALSE; 307f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 308f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl = &mt->levels[level]; 309f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!lvl->valid || 310f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->width != texImage->Width || 311f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->height != texImage->Height || 312f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org lvl->depth != texImage->Depth) 313f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_FALSE; 314f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 315f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_TRUE; 316f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 317f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 318f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 319f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Checks whether the given miptree has the right format to store the given texture object. 320f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 321f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic GLboolean radeon_miptree_matches_texture(radeon_mipmap_tree *mt, struct gl_texture_object *texObj) 322f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 323f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_texture_image *firstImage; 324f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned numLevels; 325f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_level *mtBaseLevel; 326f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 327f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (texObj->BaseLevel < mt->baseLevel) 328f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_FALSE; 329f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 330f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel = &mt->levels[texObj->BaseLevel - mt->baseLevel]; 331f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org firstImage = texObj->Image[0][texObj->BaseLevel]; 332f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org numLevels = MIN2(texObj->_MaxLevel - texObj->BaseLevel + 1, firstImage->MaxNumLevels); 333f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 334f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (radeon_is_debug_enabled(RADEON_TEXTURE,RADEON_TRACE)) { 335f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "Checking if miptree %p matches texObj %p\n", mt, texObj); 336f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "target %d vs %d\n", mt->target, texObj->Target); 337f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "format %d vs %d\n", mt->mesaFormat, firstImage->TexFormat); 338f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "numLevels %d vs %d\n", mt->numLevels, numLevels); 339f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "width0 %d vs %d\n", mtBaseLevel->width, firstImage->Width); 340f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "height0 %d vs %d\n", mtBaseLevel->height, firstImage->Height); 341f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "depth0 %d vs %d\n", mtBaseLevel->depth, firstImage->Depth); 342f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (mt->target == texObj->Target && 343f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->mesaFormat == firstImage->TexFormat && 344f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->numLevels >= numLevels && 345f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->width == firstImage->Width && 346f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->height == firstImage->Height && 347f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->depth == firstImage->Depth) { 348f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "MATCHED\n"); 349f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 350f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org fprintf(stderr, "NOT MATCHED\n"); 351f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 352f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 353f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 354f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return (mt->target == texObj->Target && 355f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->mesaFormat == firstImage->TexFormat && 356f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mt->numLevels >= numLevels && 357f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->width == firstImage->Width && 358f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->height == firstImage->Height && 359f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtBaseLevel->depth == firstImage->Depth); 360f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 361f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 362f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 363f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Try to allocate a mipmap tree for the given texture object. 364f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] rmesa radeon context 365f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] t radeon texture object 366f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 367f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgvoid radeon_try_alloc_miptree(radeonContextPtr rmesa, radeonTexObj *t) 368f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 369f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_texture_object *texObj = &t->base; 370f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_texture_image *texImg = texObj->Image[0][texObj->BaseLevel]; 371f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint numLevels; 372f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(!t->mt); 373f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 374f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!texImg) { 375f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_warning("%s(%p) No image in given texture object(%p).\n", 376f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, rmesa, t); 377f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return; 378f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 379f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 380f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 381f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org numLevels = MIN2(texObj->MaxLevel - texObj->BaseLevel + 1, texImg->MaxNumLevels); 382f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 383f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org t->mt = radeon_miptree_create(rmesa, t->base.Target, 384f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org texImg->TexFormat, texObj->BaseLevel, 385f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org numLevels, texImg->Width, texImg->Height, 386f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org texImg->Depth, t->tile_bits); 387f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 388f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 389f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgGLuint 390f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgradeon_miptree_image_offset(radeon_mipmap_tree *mt, 391f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org GLuint face, GLuint level) 392f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 393f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) 394f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return (mt->levels[level].faces[face].offset); 395f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org else 396f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return mt->levels[level].faces[0].offset; 397f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 398f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 399f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 400f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Ensure that the given image is stored in the given miptree from now on. 401f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 402f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic void migrate_image_to_miptree(radeon_mipmap_tree *mt, 403f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_texture_image *image, 404f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int face, int level) 405f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 406f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_level *dstlvl = &mt->levels[level]; 407f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned char *dest; 408f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 409f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(image->mt != mt); 410f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(dstlvl->valid); 411f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(dstlvl->width == image->base.Base.Width); 412f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(dstlvl->height == image->base.Base.Height); 413f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(dstlvl->depth == image->base.Base.Depth); 414f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 415f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_VERBOSE, 416f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s miptree %p, image %p, face %d, level %d.\n", 417f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__, mt, image, face, level); 418f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 419f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_bo_map(mt->bo, GL_TRUE); 420f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dest = mt->bo->ptr + dstlvl->faces[face].offset; 421f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 422f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (image->mt) { 423f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Format etc. should match, so we really just need a memcpy(). 424f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * In fact, that memcpy() could be done by the hardware in many 425f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * cases, provided that we have a proper memory manager. 426f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 427f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(mt->mesaFormat == image->base.Base.TexFormat); 428f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 429f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_level *srclvl = &image->mt->levels[image->base.Base.Level]; 430f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 431f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(image->base.Base.Level == level); 432f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(srclvl->size == dstlvl->size); 433f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org assert(srclvl->rowstride == dstlvl->rowstride); 434f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 435f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_bo_map(image->mt->bo, GL_FALSE); 436f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 437f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org memcpy(dest, 438f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org image->mt->bo->ptr + srclvl->faces[face].offset, 439f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dstlvl->size); 440f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_bo_unmap(image->mt->bo); 441f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 442f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_miptree_unreference(&image->mt); 443f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else if (image->base.Map) { 444f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* This condition should be removed, it's here to workaround 445f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * a segfault when mapping textures during software fallbacks. 446f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 447f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_FALLBACKS, RADEON_IMPORTANT, 448f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s Trying to map texture in software fallback.\n", 449f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __func__); 450f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const uint32_t srcrowstride = _mesa_format_row_stride(image->base.Base.TexFormat, image->base.Base.Width); 451f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org uint32_t rows = image->base.Base.Height * image->base.Base.Depth; 452f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 453f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (_mesa_is_format_compressed(image->base.Base.TexFormat)) { 454f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org uint32_t blockWidth, blockHeight; 455f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org _mesa_get_format_block_size(image->base.Base.TexFormat, &blockWidth, &blockHeight); 456f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org rows = (rows + blockHeight - 1) / blockHeight; 457f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 458f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 459f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org copy_rows(dest, dstlvl->rowstride, image->base.Map, srcrowstride, 460f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org rows, srcrowstride); 461f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 462f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org _mesa_align_free(image->base.Map); 463f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org image->base.Map = 0; 464f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 465f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 466f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_bo_unmap(mt->bo); 467f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 468f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_miptree_reference(mt, &image->mt); 469f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 470f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 471f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 472f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Filter matching miptrees, and select one with the most of data. 473f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] texObj radeon texture object 474f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] firstLevel first texture level to check 475f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * @param[in] lastLevel last texture level to check 476f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 477f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgstatic radeon_mipmap_tree * get_biggest_matching_miptree(radeonTexObj *texObj, 478f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned firstLevel, 479f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned lastLevel) 480f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 481f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const unsigned numLevels = lastLevel - firstLevel + 1; 482f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned *mtSizes = calloc(numLevels, sizeof(unsigned)); 483f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_tree **mts = calloc(numLevels, sizeof(radeon_mipmap_tree *)); 484f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned mtCount = 0; 485f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned maxMtIndex = 0; 486f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_tree *tmp; 487f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned int level; 488f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org int i; 489f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 490f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (level = firstLevel; level <= lastLevel; ++level) { 491f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_texture_image *img = get_radeon_texture_image(texObj->base.Image[0][level]); 492f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned found = 0; 493f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org // TODO: why this hack?? 494f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!img) 495f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org break; 496f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 497f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!img->mt) 498f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org continue; 499f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 500f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (i = 0; i < mtCount; ++i) { 501f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (mts[i] == img->mt) { 502f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org found = 1; 503f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtSizes[i] += img->mt->levels[img->base.Base.Level].size; 504f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org break; 505f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 506f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 507f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 508f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!found && radeon_miptree_matches_texture(img->mt, &texObj->base)) { 509f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtSizes[mtCount] = img->mt->levels[img->base.Base.Level].size; 510f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mts[mtCount] = img->mt; 511f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org mtCount++; 512f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 513f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 514f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 515f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (mtCount == 0) { 516f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org free(mtSizes); 517f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org free(mts); 518f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return NULL; 519f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 520f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 521f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (i = 1; i < mtCount; ++i) { 522f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (mtSizes[i] > mtSizes[maxMtIndex]) { 523f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org maxMtIndex = i; 524f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 525f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 526f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 527f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org tmp = mts[maxMtIndex]; 528f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org free(mtSizes); 529f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org free(mts); 530f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 531f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return tmp; 532f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 533f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 534f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org/** 535f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * Validate texture mipmap tree. 536f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * If individual images are stored in different mipmap trees 537f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org * use the mipmap tree that has the most of the correct data. 538f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org */ 539f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orgint radeon_validate_texture_miptree(struct gl_context * ctx, 540f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_sampler_object *samp, 541f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct gl_texture_object *texObj) 542f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 543f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeonContextPtr rmesa = RADEON_CONTEXT(ctx); 544f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeonTexObj *t = radeon_tex_obj(texObj); 545f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_mipmap_tree *dst_miptree; 546f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 547f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (samp == &texObj->Sampler && (t->validated || t->image_override)) { 548f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_TRUE; 549f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 550f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 551f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org calculate_min_max_lod(samp, &t->base, &t->minLod, &t->maxLod); 552f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 553f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_NORMAL, 554f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s: Validating texture %p now, minLod = %d, maxLod = %d\n", 555f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __FUNCTION__, texObj ,t->minLod, t->maxLod); 556f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 557f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org dst_miptree = get_biggest_matching_miptree(t, t->base.BaseLevel, t->base._MaxLevel); 558f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 559f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_miptree_unreference(&t->mt); 560f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!dst_miptree) { 561f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_try_alloc_miptree(rmesa, t); 562f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_NORMAL, 563f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s: No matching miptree found, allocated new one %p\n", 564f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org __FUNCTION__, t->mt); 565f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 566f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 567f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_miptree_reference(dst_miptree, &t->mt); 568f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_NORMAL, 569f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "%s: Using miptree %p\n", __FUNCTION__, t->mt); 570f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 571f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 572f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org const unsigned faces = _mesa_num_tex_faces(texObj->Target); 573f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org unsigned face, level; 574f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_texture_image *img; 575f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org /* Validate only the levels that will actually be used during rendering */ 576f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (face = 0; face < faces; ++face) { 577f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org for (level = t->minLod; level <= t->maxLod; ++level) { 578f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org img = get_radeon_texture_image(texObj->Image[face][level]); 579f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 580f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 581f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "Checking image level %d, face %d, mt %p ... ", 582f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org level, face, img->mt); 583f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 584f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (img->mt != t->mt && !img->used_as_render_target) { 585f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, 586f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org "MIGRATING\n"); 587f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 588f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org struct radeon_bo *src_bo = (img->mt) ? img->mt->bo : img->bo; 589f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (src_bo && radeon_bo_is_referenced_by_cs(src_bo, rmesa->cmdbuf.cs)) { 590f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_firevertices(rmesa); 591f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 592f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org migrate_image_to_miptree(t->mt, img, face, level); 593f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else 594f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org radeon_print(RADEON_TEXTURE, RADEON_TRACE, "OK\n"); 595f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 596f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 597f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 598f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org t->validated = GL_TRUE; 599f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 600f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return GL_TRUE; 601f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 602f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org 603f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.orguint32_t get_base_teximage_offset(radeonTexObj *texObj) 604f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org{ 605f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org if (!texObj->mt) { 606f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return 0; 607f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } else { 608f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org return radeon_miptree_image_offset(texObj->mt, 0, texObj->minLod); 609f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org } 610f2ba7591b1407a7ee9209f842c50696914dc2dedkbr@chromium.org} 611