Path: blob/21.2-virgl/src/gallium/drivers/r300/r300_texture_desc.c
4570 views
/*1* Copyright 2008 Corbin Simpson <[email protected]>2* Copyright 2010 Marek Olšák <[email protected]>3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* on the rights to use, copy, modify, merge, publish, distribute, sub8* license, and/or sell copies of the Software, and to permit persons to whom9* the Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL18* THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,19* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR20* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE21* USE OR OTHER DEALINGS IN THE SOFTWARE. */2223#include "r300_texture_desc.h"24#include "r300_context.h"2526#include "util/format/u_format.h"27#include <inttypes.h>2829/* Returns the number of pixels that the texture should be aligned to30* in the given dimension. */31unsigned r300_get_pixel_alignment(enum pipe_format format,32unsigned num_samples,33enum radeon_bo_layout microtile,34enum radeon_bo_layout macrotile,35enum r300_dim dim, boolean is_rs690)36{37static const unsigned table[2][5][3][2] =38{39{40/* Macro: linear linear linear41Micro: linear tiled square-tiled */42{{ 32, 1}, { 8, 4}, { 0, 0}}, /* 8 bits per pixel */43{{ 16, 1}, { 8, 2}, { 4, 4}}, /* 16 bits per pixel */44{{ 8, 1}, { 4, 2}, { 0, 0}}, /* 32 bits per pixel */45{{ 4, 1}, { 2, 2}, { 0, 0}}, /* 64 bits per pixel */46{{ 2, 1}, { 0, 0}, { 0, 0}} /* 128 bits per pixel */47},48{49/* Macro: tiled tiled tiled50Micro: linear tiled square-tiled */51{{256, 8}, {64, 32}, { 0, 0}}, /* 8 bits per pixel */52{{128, 8}, {64, 16}, {32, 32}}, /* 16 bits per pixel */53{{ 64, 8}, {32, 16}, { 0, 0}}, /* 32 bits per pixel */54{{ 32, 8}, {16, 16}, { 0, 0}}, /* 64 bits per pixel */55{{ 16, 8}, { 0, 0}, { 0, 0}} /* 128 bits per pixel */56}57};5859unsigned tile = 0;60unsigned pixsize = util_format_get_blocksize(format);6162assert(macrotile <= RADEON_LAYOUT_TILED);63assert(microtile <= RADEON_LAYOUT_SQUARETILED);64assert(pixsize <= 16);65assert(dim <= DIM_HEIGHT);6667tile = table[macrotile][util_logbase2(pixsize)][microtile][dim];68if (macrotile == 0 && is_rs690 && dim == DIM_WIDTH) {69int align;70int h_tile;71h_tile = table[macrotile][util_logbase2(pixsize)][microtile][DIM_HEIGHT];72align = 64 / (pixsize * h_tile);73if (tile < align)74tile = align;75}7677assert(tile);78return tile;79}8081/* Return true if macrotiling should be enabled on the miplevel. */82static boolean r300_texture_macro_switch(struct r300_resource *tex,83unsigned level,84boolean rv350_mode,85enum r300_dim dim)86{87unsigned tile, texdim;8889if (tex->b.nr_samples > 1) {90return TRUE;91}9293tile = r300_get_pixel_alignment(tex->b.format, tex->b.nr_samples,94tex->tex.microtile, RADEON_LAYOUT_TILED, dim, 0);95if (dim == DIM_WIDTH) {96texdim = u_minify(tex->tex.width0, level);97} else {98texdim = u_minify(tex->tex.height0, level);99}100101/* See TX_FILTER1_n.MACRO_SWITCH. */102if (rv350_mode) {103return texdim >= tile;104} else {105return texdim > tile;106}107}108109/**110* Return the stride, in bytes, of the texture image of the given texture111* at the given level.112*/113static unsigned r300_texture_get_stride(struct r300_screen *screen,114struct r300_resource *tex,115unsigned level)116{117unsigned tile_width, width, stride;118boolean is_rs690 = (screen->caps.family == CHIP_RS600 ||119screen->caps.family == CHIP_RS690 ||120screen->caps.family == CHIP_RS740);121122if (tex->tex.stride_in_bytes_override)123return tex->tex.stride_in_bytes_override;124125/* Check the level. */126if (level > tex->b.last_level) {127SCREEN_DBG(screen, DBG_TEX, "%s: level (%u) > last_level (%u)\n",128__FUNCTION__, level, tex->b.last_level);129return 0;130}131132width = u_minify(tex->tex.width0, level);133134if (util_format_is_plain(tex->b.format)) {135tile_width = r300_get_pixel_alignment(tex->b.format,136tex->b.nr_samples,137tex->tex.microtile,138tex->tex.macrotile[level],139DIM_WIDTH, is_rs690);140width = align(width, tile_width);141142stride = util_format_get_stride(tex->b.format, width);143/* The alignment to 32 bytes is sort of implied by the layout... */144return stride;145} else {146return align(util_format_get_stride(tex->b.format, width), is_rs690 ? 64 : 32);147}148}149150static unsigned r300_texture_get_nblocksy(struct r300_resource *tex,151unsigned level,152boolean *out_aligned_for_cbzb)153{154unsigned height, tile_height;155156height = u_minify(tex->tex.height0, level);157158/* Mipmapped and 3D textures must have their height aligned to POT. */159if ((tex->b.target != PIPE_TEXTURE_1D &&160tex->b.target != PIPE_TEXTURE_2D &&161tex->b.target != PIPE_TEXTURE_RECT) ||162tex->b.last_level != 0) {163height = util_next_power_of_two(height);164}165166if (util_format_is_plain(tex->b.format)) {167tile_height = r300_get_pixel_alignment(tex->b.format,168tex->b.nr_samples,169tex->tex.microtile,170tex->tex.macrotile[level],171DIM_HEIGHT, 0);172height = align(height, tile_height);173174/* See if the CBZB clear can be used on the buffer,175* taking the texture size into account. */176if (out_aligned_for_cbzb) {177if (tex->tex.macrotile[level]) {178/* When clearing, the layer (width*height) is horizontally split179* into two, and the upper and lower halves are cleared by the CB180* and ZB units, respectively. Therefore, the number of macrotiles181* in the Y direction must be even. */182183/* Align the height so that there is an even number of macrotiles.184* Do so for 3 or more macrotiles in the Y direction. */185if (level == 0 && tex->b.last_level == 0 &&186(tex->b.target == PIPE_TEXTURE_1D ||187tex->b.target == PIPE_TEXTURE_2D ||188tex->b.target == PIPE_TEXTURE_RECT) &&189height >= tile_height * 3) {190height = align(height, tile_height * 2);191}192193*out_aligned_for_cbzb = height % (tile_height * 2) == 0;194} else {195*out_aligned_for_cbzb = FALSE;196}197}198}199200return util_format_get_nblocksy(tex->b.format, height);201}202203/* Get a width in pixels from a stride in bytes. */204unsigned r300_stride_to_width(enum pipe_format format,205unsigned stride_in_bytes)206{207return (stride_in_bytes / util_format_get_blocksize(format)) *208util_format_get_blockwidth(format);209}210211static void r300_setup_miptree(struct r300_screen *screen,212struct r300_resource *tex,213boolean align_for_cbzb)214{215struct pipe_resource *base = &tex->b;216unsigned stride, size, layer_size, nblocksy, i;217boolean rv350_mode = screen->caps.family >= CHIP_R350;218boolean aligned_for_cbzb;219220tex->tex.size_in_bytes = 0;221222SCREEN_DBG(screen, DBG_TEXALLOC,223"r300: Making miptree for texture, format %s\n",224util_format_short_name(base->format));225226for (i = 0; i <= base->last_level; i++) {227/* Let's see if this miplevel can be macrotiled. */228tex->tex.macrotile[i] =229(tex->tex.macrotile[0] == RADEON_LAYOUT_TILED &&230r300_texture_macro_switch(tex, i, rv350_mode, DIM_WIDTH) &&231r300_texture_macro_switch(tex, i, rv350_mode, DIM_HEIGHT)) ?232RADEON_LAYOUT_TILED : RADEON_LAYOUT_LINEAR;233234stride = r300_texture_get_stride(screen, tex, i);235236/* Compute the number of blocks in Y, see if the CBZB clear can be237* used on the texture. */238aligned_for_cbzb = FALSE;239if (align_for_cbzb && tex->tex.cbzb_allowed[i])240nblocksy = r300_texture_get_nblocksy(tex, i, &aligned_for_cbzb);241else242nblocksy = r300_texture_get_nblocksy(tex, i, NULL);243244layer_size = stride * nblocksy;245246if (base->nr_samples > 1) {247layer_size *= base->nr_samples;248}249250if (base->target == PIPE_TEXTURE_CUBE)251size = layer_size * 6;252else253size = layer_size * u_minify(tex->tex.depth0, i);254255tex->tex.offset_in_bytes[i] = tex->tex.size_in_bytes;256tex->tex.size_in_bytes = tex->tex.offset_in_bytes[i] + size;257tex->tex.layer_size_in_bytes[i] = layer_size;258tex->tex.stride_in_bytes[i] = stride;259tex->tex.cbzb_allowed[i] = tex->tex.cbzb_allowed[i] && aligned_for_cbzb;260261SCREEN_DBG(screen, DBG_TEXALLOC, "r300: Texture miptree: Level %d "262"(%dx%dx%d px, pitch %d bytes) %d bytes total, macrotiled %s\n",263i, u_minify(tex->tex.width0, i), u_minify(tex->tex.height0, i),264u_minify(tex->tex.depth0, i), stride, tex->tex.size_in_bytes,265tex->tex.macrotile[i] ? "TRUE" : "FALSE");266}267}268269static void r300_setup_flags(struct r300_resource *tex)270{271tex->tex.uses_stride_addressing =272!util_is_power_of_two_or_zero(tex->b.width0) ||273(tex->tex.stride_in_bytes_override &&274r300_stride_to_width(tex->b.format,275tex->tex.stride_in_bytes_override) != tex->b.width0);276277tex->tex.is_npot =278tex->tex.uses_stride_addressing ||279!util_is_power_of_two_or_zero(tex->b.height0) ||280!util_is_power_of_two_or_zero(tex->b.depth0);281}282283static void r300_setup_cbzb_flags(struct r300_screen *rscreen,284struct r300_resource *tex)285{286unsigned i, bpp;287boolean first_level_valid;288289bpp = util_format_get_blocksizebits(tex->b.format);290291/* 1) The texture must be point-sampled,292* 2) The depth must be 16 or 32 bits.293* 3) If the midpoint ZB offset is not aligned to 2048, it returns garbage294* with certain texture sizes. Macrotiling ensures the alignment. */295first_level_valid = tex->b.nr_samples <= 1 &&296(bpp == 16 || bpp == 32) &&297tex->tex.macrotile[0];298299if (SCREEN_DBG_ON(rscreen, DBG_NO_CBZB))300first_level_valid = FALSE;301302for (i = 0; i <= tex->b.last_level; i++)303tex->tex.cbzb_allowed[i] = first_level_valid && tex->tex.macrotile[i];304}305306static unsigned r300_pixels_to_dwords(unsigned stride,307unsigned height,308unsigned xblock, unsigned yblock)309{310return (util_align_npot(stride, xblock) * align(height, yblock)) / (xblock * yblock);311}312313static void r300_setup_hyperz_properties(struct r300_screen *screen,314struct r300_resource *tex)315{316/* The tile size of 1 DWORD in ZMASK RAM is:317*318* GPU Pipes 4x4 mode 8x8 mode319* ------------------------------------------320* R580 4P/1Z 32x32 64x64321* RV570 3P/1Z 48x16 96x32322* RV530 1P/2Z 32x16 64x32323* 1P/1Z 16x16 32x32324*/325static unsigned zmask_blocks_x_per_dw[4] = {4, 8, 12, 8};326static unsigned zmask_blocks_y_per_dw[4] = {4, 4, 4, 8};327328/* In HIZ RAM, one dword is always 8x8 pixels (each byte is 4x4 pixels),329* but the blocks have very weird ordering.330*331* With 2 pipes and an image of size 8xY, where Y >= 1,332* clearing 4 dwords clears blocks like this:333*334* 01012323335*336* where numbers correspond to dword indices. The blocks are interleaved337* in the X direction, so the alignment must be 4x1 blocks (32x8 pixels).338*339* With 4 pipes and an image of size 8xY, where Y >= 4,340* clearing 8 dwords clears blocks like this:341* 01012323342* 45456767343* 01012323344* 45456767345* where numbers correspond to dword indices. The blocks are interleaved346* in both directions, so the alignment must be 4x4 blocks (32x32 pixels)347*/348static unsigned hiz_align_x[4] = {8, 32, 48, 32};349static unsigned hiz_align_y[4] = {8, 8, 8, 32};350351if (util_format_is_depth_or_stencil(tex->b.format) &&352util_format_get_blocksizebits(tex->b.format) == 32 &&353tex->tex.microtile) {354unsigned i, pipes;355356if (screen->caps.family == CHIP_RV530) {357pipes = screen->info.r300_num_z_pipes;358} else {359pipes = screen->info.r300_num_gb_pipes;360}361362for (i = 0; i <= tex->b.last_level; i++) {363unsigned zcomp_numdw, zcompsize, hiz_numdw, stride, height;364365stride = r300_stride_to_width(tex->b.format,366tex->tex.stride_in_bytes[i]);367stride = align(stride, 16);368height = u_minify(tex->b.height0, i);369370/* The 8x8 compression mode needs macrotiling. */371zcompsize = screen->caps.z_compress == R300_ZCOMP_8X8 &&372tex->tex.macrotile[i] &&373tex->b.nr_samples <= 1 ? 8 : 4;374375/* Get the ZMASK buffer size in dwords. */376zcomp_numdw = r300_pixels_to_dwords(stride, height,377zmask_blocks_x_per_dw[pipes-1] * zcompsize,378zmask_blocks_y_per_dw[pipes-1] * zcompsize);379380/* Check whether we have enough ZMASK memory. */381if (util_format_get_blocksizebits(tex->b.format) == 32 &&382zcomp_numdw <= screen->caps.zmask_ram * pipes) {383tex->tex.zmask_dwords[i] = zcomp_numdw;384tex->tex.zcomp8x8[i] = zcompsize == 8;385386tex->tex.zmask_stride_in_pixels[i] =387util_align_npot(stride, zmask_blocks_x_per_dw[pipes-1] * zcompsize);388} else {389tex->tex.zmask_dwords[i] = 0;390tex->tex.zcomp8x8[i] = FALSE;391tex->tex.zmask_stride_in_pixels[i] = 0;392}393394/* Now setup HIZ. */395stride = util_align_npot(stride, hiz_align_x[pipes-1]);396height = align(height, hiz_align_y[pipes-1]);397398/* Get the HIZ buffer size in dwords. */399hiz_numdw = (stride * height) / (8*8 * pipes);400401/* Check whether we have enough HIZ memory. */402if (hiz_numdw <= screen->caps.hiz_ram * pipes) {403tex->tex.hiz_dwords[i] = hiz_numdw;404tex->tex.hiz_stride_in_pixels[i] = stride;405} else {406tex->tex.hiz_dwords[i] = 0;407tex->tex.hiz_stride_in_pixels[i] = 0;408}409}410}411}412413static void r300_setup_cmask_properties(struct r300_screen *screen,414struct r300_resource *tex)415{416static unsigned cmask_align_x[4] = {16, 32, 48, 32};417static unsigned cmask_align_y[4] = {16, 16, 16, 32};418unsigned pipes, stride, cmask_num_dw, cmask_max_size;419420if (!screen->caps.has_cmask) {421return;422}423424/* We need an AA colorbuffer, no mipmaps. */425if (tex->b.nr_samples <= 1 ||426tex->b.last_level > 0 ||427util_format_is_depth_or_stencil(tex->b.format)) {428return;429}430431/* FP16 AA needs R500 and a fairly new DRM. */432if ((tex->b.format == PIPE_FORMAT_R16G16B16A16_FLOAT ||433tex->b.format == PIPE_FORMAT_R16G16B16X16_FLOAT) &&434(!screen->caps.is_r500 || screen->info.drm_minor < 29)) {435return;436}437438if (SCREEN_DBG_ON(screen, DBG_NO_CMASK)) {439return;440}441442/* CMASK is part of raster pipes. The number of Z pipes doesn't matter. */443pipes = screen->info.r300_num_gb_pipes;444445/* The single-pipe cards have 5120 dwords of CMASK RAM,446* the other cards have 4096 dwords of CMASK RAM per pipe. */447cmask_max_size = pipes == 1 ? 5120 : pipes * 4096;448449stride = r300_stride_to_width(tex->b.format,450tex->tex.stride_in_bytes[0]);451stride = align(stride, 16);452453/* Get the CMASK size in dwords. */454cmask_num_dw = r300_pixels_to_dwords(stride, tex->b.height0,455cmask_align_x[pipes-1],456cmask_align_y[pipes-1]);457458/* Check the CMASK size against the CMASK memory limit. */459if (cmask_num_dw <= cmask_max_size) {460tex->tex.cmask_dwords = cmask_num_dw;461tex->tex.cmask_stride_in_pixels =462util_align_npot(stride, cmask_align_x[pipes-1]);463}464}465466static void r300_setup_tiling(struct r300_screen *screen,467struct r300_resource *tex)468{469enum pipe_format format = tex->b.format;470boolean rv350_mode = screen->caps.family >= CHIP_R350;471boolean is_zb = util_format_is_depth_or_stencil(format);472boolean dbg_no_tiling = SCREEN_DBG_ON(screen, DBG_NO_TILING);473boolean force_microtiling =474(tex->b.flags & R300_RESOURCE_FORCE_MICROTILING) != 0;475476if (tex->b.nr_samples > 1) {477tex->tex.microtile = RADEON_LAYOUT_TILED;478tex->tex.macrotile[0] = RADEON_LAYOUT_TILED;479return;480}481482tex->tex.microtile = RADEON_LAYOUT_LINEAR;483tex->tex.macrotile[0] = RADEON_LAYOUT_LINEAR;484485if (tex->b.usage == PIPE_USAGE_STAGING) {486return;487}488489if (!util_format_is_plain(format)) {490return;491}492493/* If height == 1, disable microtiling except for zbuffer. */494if (!force_microtiling && !is_zb &&495(tex->b.height0 == 1 || dbg_no_tiling)) {496return;497}498499/* Set microtiling. */500switch (util_format_get_blocksize(format)) {501case 1:502case 4:503case 8:504tex->tex.microtile = RADEON_LAYOUT_TILED;505break;506507case 2:508tex->tex.microtile = RADEON_LAYOUT_SQUARETILED;509break;510}511512if (dbg_no_tiling) {513return;514}515516/* Set macrotiling. */517if (r300_texture_macro_switch(tex, 0, rv350_mode, DIM_WIDTH) &&518r300_texture_macro_switch(tex, 0, rv350_mode, DIM_HEIGHT)) {519tex->tex.macrotile[0] = RADEON_LAYOUT_TILED;520}521}522523static void r300_tex_print_info(struct r300_resource *tex,524const char *func)525{526fprintf(stderr,527"r300: %s: Macro: %s, Micro: %s, Pitch: %i, Dim: %ix%ix%i, "528"LastLevel: %i, Size: %i, Format: %s, Samples: %i\n",529func,530tex->tex.macrotile[0] ? "YES" : " NO",531tex->tex.microtile ? "YES" : " NO",532r300_stride_to_width(tex->b.format, tex->tex.stride_in_bytes[0]),533tex->b.width0, tex->b.height0, tex->b.depth0,534tex->b.last_level, tex->tex.size_in_bytes,535util_format_short_name(tex->b.format),536tex->b.nr_samples);537}538539void r300_texture_desc_init(struct r300_screen *rscreen,540struct r300_resource *tex,541const struct pipe_resource *base)542{543tex->b.target = base->target;544tex->b.format = base->format;545tex->b.width0 = base->width0;546tex->b.height0 = base->height0;547tex->b.depth0 = base->depth0;548tex->b.array_size = base->array_size;549tex->b.last_level = base->last_level;550tex->b.nr_samples = base->nr_samples;551tex->tex.width0 = base->width0;552tex->tex.height0 = base->height0;553tex->tex.depth0 = base->depth0;554555/* There is a CB memory addressing hardware bug that limits the width556* of the MSAA buffer in some cases in R520. In order to get around it,557* the following code lowers the sample count depending on the format and558* the width.559*560* The only catch is that all MSAA colorbuffers and a zbuffer which are561* supposed to be used together should always be bound together. Only562* then the correct minimum sample count of all bound buffers is used563* for rendering. */564if (rscreen->caps.is_r500) {565/* FP16 6x MSAA buffers are limited to a width of 1360 pixels. */566if ((tex->b.format == PIPE_FORMAT_R16G16B16A16_FLOAT ||567tex->b.format == PIPE_FORMAT_R16G16B16X16_FLOAT) &&568tex->b.nr_samples == 6 && tex->b.width0 > 1360) {569tex->b.nr_samples = 4;570}571572/* FP16 4x MSAA buffers are limited to a width of 2048 pixels. */573if ((tex->b.format == PIPE_FORMAT_R16G16B16A16_FLOAT ||574tex->b.format == PIPE_FORMAT_R16G16B16X16_FLOAT) &&575tex->b.nr_samples == 4 && tex->b.width0 > 2048) {576tex->b.nr_samples = 2;577}578}579580/* 32-bit 6x MSAA buffers are limited to a width of 2720 pixels.581* This applies to all R300-R500 cards. */582if (util_format_get_blocksizebits(tex->b.format) == 32 &&583!util_format_is_depth_or_stencil(tex->b.format) &&584tex->b.nr_samples == 6 && tex->b.width0 > 2720) {585tex->b.nr_samples = 4;586}587588r300_setup_flags(tex);589590/* Align a 3D NPOT texture to POT. */591if (base->target == PIPE_TEXTURE_3D && tex->tex.is_npot) {592tex->tex.width0 = util_next_power_of_two(tex->tex.width0);593tex->tex.height0 = util_next_power_of_two(tex->tex.height0);594tex->tex.depth0 = util_next_power_of_two(tex->tex.depth0);595}596597/* Setup tiling. */598if (tex->tex.microtile == RADEON_LAYOUT_UNKNOWN) {599r300_setup_tiling(rscreen, tex);600}601602r300_setup_cbzb_flags(rscreen, tex);603604/* Setup the miptree description. */605r300_setup_miptree(rscreen, tex, TRUE);606/* If the required buffer size is larger than the given max size,607* try again without the alignment for the CBZB clear. */608if (tex->buf && tex->tex.size_in_bytes > tex->buf->size) {609r300_setup_miptree(rscreen, tex, FALSE);610611/* Make sure the buffer we got is large enough. */612if (tex->tex.size_in_bytes > tex->buf->size) {613fprintf(stderr,614"r300: I got a pre-allocated buffer to use it as a texture "615"storage, but the buffer is too small. I'll use the buffer "616"anyway, because I can't crash here, but it's dangerous. "617"This can be a DDX bug. Got: %"PRIu64"B, Need: %uB, Info:\n",618tex->buf->size, tex->tex.size_in_bytes);619r300_tex_print_info(tex, "texture_desc_init");620/* Oops, what now. Apps will break if we fail this,621* so just pretend everything's okay. */622}623}624625r300_setup_hyperz_properties(rscreen, tex);626r300_setup_cmask_properties(rscreen, tex);627628if (SCREEN_DBG_ON(rscreen, DBG_TEX))629r300_tex_print_info(tex, "texture_desc_init");630}631632unsigned r300_texture_get_offset(struct r300_resource *tex,633unsigned level, unsigned layer)634{635unsigned offset = tex->tex.offset_in_bytes[level];636637switch (tex->b.target) {638case PIPE_TEXTURE_3D:639case PIPE_TEXTURE_CUBE:640return offset + layer * tex->tex.layer_size_in_bytes[level];641642default:643assert(layer == 0);644return offset;645}646}647648649