1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Mesa 3-D graphics library 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Copyright (C) 2014 Intel Corporation. All Rights Reserved. 5bf215546Sopenharmony_ci * 6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 12bf215546Sopenharmony_ci * 13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included 14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 15bf215546Sopenharmony_ci * 16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 23bf215546Sopenharmony_ci * 24bf215546Sopenharmony_ci * Authors: 25bf215546Sopenharmony_ci * Jason Ekstrand <jason.ekstrand@intel.com> 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "context.h" 29bf215546Sopenharmony_ci#include "glheader.h" 30bf215546Sopenharmony_ci#include "errors.h" 31bf215546Sopenharmony_ci#include "enums.h" 32bf215546Sopenharmony_ci#include "teximage.h" 33bf215546Sopenharmony_ci#include "texobj.h" 34bf215546Sopenharmony_ci#include "fbobject.h" 35bf215546Sopenharmony_ci#include "textureview.h" 36bf215546Sopenharmony_ci#include "glformats.h" 37bf215546Sopenharmony_ci#include "api_exec_decl.h" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "state_tracker/st_cb_copyimage.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cienum mesa_block_class { 42bf215546Sopenharmony_ci BLOCK_CLASS_128_BITS, 43bf215546Sopenharmony_ci BLOCK_CLASS_64_BITS 44bf215546Sopenharmony_ci}; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci/** 47bf215546Sopenharmony_ci * Prepare the source or destination resource. This involves error 48bf215546Sopenharmony_ci * checking and returning the relevant gl_texture_image or gl_renderbuffer. 49bf215546Sopenharmony_ci * Note that one of the resulting tex_image or renderbuffer pointers will be 50bf215546Sopenharmony_ci * NULL and the other will be non-null. 51bf215546Sopenharmony_ci * 52bf215546Sopenharmony_ci * \param name the texture or renderbuffer name 53bf215546Sopenharmony_ci * \param target One of GL_TEXTURE_x target or GL_RENDERBUFFER 54bf215546Sopenharmony_ci * \param level mipmap level 55bf215546Sopenharmony_ci * \param z src or dest Z 56bf215546Sopenharmony_ci * \param depth number of slices/faces/layers to copy 57bf215546Sopenharmony_ci * \param tex_image returns a pointer to a texture image 58bf215546Sopenharmony_ci * \param renderbuffer returns a pointer to a renderbuffer 59bf215546Sopenharmony_ci * \return true if success, false if error 60bf215546Sopenharmony_ci */ 61bf215546Sopenharmony_cistatic bool 62bf215546Sopenharmony_ciprepare_target_err(struct gl_context *ctx, GLuint name, GLenum target, 63bf215546Sopenharmony_ci int level, int z, int depth, 64bf215546Sopenharmony_ci struct gl_texture_image **tex_image, 65bf215546Sopenharmony_ci struct gl_renderbuffer **renderbuffer, 66bf215546Sopenharmony_ci mesa_format *format, 67bf215546Sopenharmony_ci GLenum *internalFormat, 68bf215546Sopenharmony_ci GLuint *width, 69bf215546Sopenharmony_ci GLuint *height, 70bf215546Sopenharmony_ci GLuint *num_samples, 71bf215546Sopenharmony_ci const char *dbg_prefix, 72bf215546Sopenharmony_ci bool is_arb_version) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci const char *suffix = is_arb_version ? "" : "NV"; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_ci if (name == 0) { 77bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 78bf215546Sopenharmony_ci "glCopyImageSubData%s(%sName = %d)", suffix, dbg_prefix, name); 79bf215546Sopenharmony_ci return false; 80bf215546Sopenharmony_ci } 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci /* 83bf215546Sopenharmony_ci * INVALID_ENUM is generated 84bf215546Sopenharmony_ci * * if either <srcTarget> or <dstTarget> 85bf215546Sopenharmony_ci * - is not RENDERBUFFER or a valid non-proxy texture target 86bf215546Sopenharmony_ci * - is TEXTURE_BUFFER, or 87bf215546Sopenharmony_ci * - is one of the cubemap face selectors described in table 3.17, 88bf215546Sopenharmony_ci */ 89bf215546Sopenharmony_ci switch (target) { 90bf215546Sopenharmony_ci case GL_RENDERBUFFER: 91bf215546Sopenharmony_ci /* Not a texture target, but valid */ 92bf215546Sopenharmony_ci case GL_TEXTURE_1D: 93bf215546Sopenharmony_ci case GL_TEXTURE_1D_ARRAY: 94bf215546Sopenharmony_ci case GL_TEXTURE_2D: 95bf215546Sopenharmony_ci case GL_TEXTURE_3D: 96bf215546Sopenharmony_ci case GL_TEXTURE_CUBE_MAP: 97bf215546Sopenharmony_ci case GL_TEXTURE_RECTANGLE: 98bf215546Sopenharmony_ci case GL_TEXTURE_2D_ARRAY: 99bf215546Sopenharmony_ci case GL_TEXTURE_CUBE_MAP_ARRAY: 100bf215546Sopenharmony_ci case GL_TEXTURE_2D_MULTISAMPLE: 101bf215546Sopenharmony_ci case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 102bf215546Sopenharmony_ci /* These are all valid */ 103bf215546Sopenharmony_ci break; 104bf215546Sopenharmony_ci case GL_TEXTURE_EXTERNAL_OES: 105bf215546Sopenharmony_ci /* Only exists in ES */ 106bf215546Sopenharmony_ci case GL_TEXTURE_BUFFER: 107bf215546Sopenharmony_ci default: 108bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_ENUM, 109bf215546Sopenharmony_ci "glCopyImageSubData%s(%sTarget = %s)", suffix, dbg_prefix, 110bf215546Sopenharmony_ci _mesa_enum_to_string(target)); 111bf215546Sopenharmony_ci return false; 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci if (target == GL_RENDERBUFFER) { 115bf215546Sopenharmony_ci struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci if (!rb) { 118bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 119bf215546Sopenharmony_ci "glCopyImageSubData%s(%sName = %u)", suffix, dbg_prefix, name); 120bf215546Sopenharmony_ci return false; 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci if (!rb->Name) { 124bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 125bf215546Sopenharmony_ci "glCopyImageSubData%s(%sName incomplete)", suffix, dbg_prefix); 126bf215546Sopenharmony_ci return false; 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci if (level != 0) { 130bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 131bf215546Sopenharmony_ci "glCopyImageSubData%s(%sLevel = %u)", suffix, dbg_prefix, level); 132bf215546Sopenharmony_ci return false; 133bf215546Sopenharmony_ci } 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci *renderbuffer = rb; 136bf215546Sopenharmony_ci *format = rb->Format; 137bf215546Sopenharmony_ci *internalFormat = rb->InternalFormat; 138bf215546Sopenharmony_ci *width = rb->Width; 139bf215546Sopenharmony_ci *height = rb->Height; 140bf215546Sopenharmony_ci *num_samples = rb->NumSamples; 141bf215546Sopenharmony_ci *tex_image = NULL; 142bf215546Sopenharmony_ci } else { 143bf215546Sopenharmony_ci struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci if (!texObj) { 146bf215546Sopenharmony_ci /* 147bf215546Sopenharmony_ci * From GL_ARB_copy_image specification: 148bf215546Sopenharmony_ci * "INVALID_VALUE is generated if either <srcName> or <dstName> does 149bf215546Sopenharmony_ci * not correspond to a valid renderbuffer or texture object according 150bf215546Sopenharmony_ci * to the corresponding target parameter." 151bf215546Sopenharmony_ci */ 152bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 153bf215546Sopenharmony_ci "glCopyImageSubData%s(%sName = %u)", suffix, dbg_prefix, name); 154bf215546Sopenharmony_ci return false; 155bf215546Sopenharmony_ci } 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci /* The ARB_copy_image specification says: 158bf215546Sopenharmony_ci * 159bf215546Sopenharmony_ci * "INVALID_OPERATION is generated if either object is a texture and 160bf215546Sopenharmony_ci * the texture is not complete (as defined in section 3.9.14)" 161bf215546Sopenharmony_ci * 162bf215546Sopenharmony_ci * The cited section says: 163bf215546Sopenharmony_ci * 164bf215546Sopenharmony_ci * "Using the preceding definitions, a texture is complete unless any 165bf215546Sopenharmony_ci * of the following conditions hold true: [...] 166bf215546Sopenharmony_ci * 167bf215546Sopenharmony_ci * * The minification filter requires a mipmap (is neither NEAREST 168bf215546Sopenharmony_ci * nor LINEAR), and the texture is not mipmap complete." 169bf215546Sopenharmony_ci * 170bf215546Sopenharmony_ci * This imposes the bizarre restriction that glCopyImageSubData requires 171bf215546Sopenharmony_ci * mipmap completion based on the sampler minification filter, even 172bf215546Sopenharmony_ci * though the call fundamentally ignores the sampler. Additionally, it 173bf215546Sopenharmony_ci * doesn't work with texture units, so it can't consider any bound 174bf215546Sopenharmony_ci * separate sampler objects. It appears that you're supposed to use 175bf215546Sopenharmony_ci * the sampler object which is built-in to the texture object. 176bf215546Sopenharmony_ci * 177bf215546Sopenharmony_ci * dEQP and the Android CTS mandate this behavior, and the Khronos 178bf215546Sopenharmony_ci * GL and ES working groups both affirmed that this is unfortunate but 179bf215546Sopenharmony_ci * correct. See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16224. 180bf215546Sopenharmony_ci * 181bf215546Sopenharmony_ci * Integer textures with filtering cause another completeness snag: 182bf215546Sopenharmony_ci * 183bf215546Sopenharmony_ci * "Any of: 184bf215546Sopenharmony_ci * – The internal format of the texture is integer (see table 8.12). 185bf215546Sopenharmony_ci * – The internal format is STENCIL_INDEX. 186bf215546Sopenharmony_ci * – The internal format is DEPTH_STENCIL, and the value of 187bf215546Sopenharmony_ci * DEPTH_STENCIL_TEXTURE_MODE for the texture is STENCIL_INDEX. 188bf215546Sopenharmony_ci * and either the magnification filter is not NEAREST, or the 189bf215546Sopenharmony_ci * minification filter is neither NEAREST nor 190bf215546Sopenharmony_ci * NEAREST_MIPMAP_NEAREST." 191bf215546Sopenharmony_ci * 192bf215546Sopenharmony_ci * However, applications in the wild (such as "Total War: WARHAMMER") 193bf215546Sopenharmony_ci * appear to call glCopyImageSubData with integer textures and the 194bf215546Sopenharmony_ci * default mipmap filters of GL_LINEAR and GL_NEAREST_MIPMAP_LINEAR, 195bf215546Sopenharmony_ci * which would be considered incomplete, but expect this to work. In 196bf215546Sopenharmony_ci * fact, until VK-GL-CTS commit fef80039ff875a51806b54d151c5f2d0c12da, 197bf215546Sopenharmony_ci * the GL 4.5 CTS contained three tests which did the exact same thing 198bf215546Sopenharmony_ci * by accident, and all conformant implementations allowed it. 199bf215546Sopenharmony_ci * 200bf215546Sopenharmony_ci * A proposal was made to amend the spec to say "is not complete (as 201bf215546Sopenharmony_ci * defined in section <X>, but ignoring format-based completeness 202bf215546Sopenharmony_ci * rules)" to allow this case. It makes some sense, given that 203bf215546Sopenharmony_ci * glCopyImageSubData copies raw data without considering format. 204bf215546Sopenharmony_ci * While the official edits have not yet been made, the OpenGL 205bf215546Sopenharmony_ci * working group agreed with the idea of allowing this behavior. 206bf215546Sopenharmony_ci * 207bf215546Sopenharmony_ci * To ignore formats, we check texObj->_MipmapComplete directly 208bf215546Sopenharmony_ci * rather than calling _mesa_is_texture_complete(). 209bf215546Sopenharmony_ci */ 210bf215546Sopenharmony_ci _mesa_test_texobj_completeness(ctx, texObj); 211bf215546Sopenharmony_ci const bool texture_complete_aside_from_formats = 212bf215546Sopenharmony_ci _mesa_is_mipmap_filter(&texObj->Sampler) ? texObj->_MipmapComplete 213bf215546Sopenharmony_ci : texObj->_BaseComplete; 214bf215546Sopenharmony_ci if (!texture_complete_aside_from_formats) { 215bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 216bf215546Sopenharmony_ci "glCopyImageSubData%s(%sName incomplete)", suffix, dbg_prefix); 217bf215546Sopenharmony_ci return false; 218bf215546Sopenharmony_ci } 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci /* Note that target will not be a cube face name */ 221bf215546Sopenharmony_ci if (texObj->Target != target) { 222bf215546Sopenharmony_ci /* 223bf215546Sopenharmony_ci * From GL_ARB_copy_image_specification: 224bf215546Sopenharmony_ci * "INVALID_ENUM is generated if the target does not match the type 225bf215546Sopenharmony_ci * of the object." 226bf215546Sopenharmony_ci */ 227bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_ENUM, 228bf215546Sopenharmony_ci "glCopyImageSubData%s(%sTarget = %s)", suffix, dbg_prefix, 229bf215546Sopenharmony_ci _mesa_enum_to_string(target)); 230bf215546Sopenharmony_ci return false; 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci if (level < 0 || level >= MAX_TEXTURE_LEVELS) { 234bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 235bf215546Sopenharmony_ci "glCopyImageSubData%s(%sLevel = %d)", suffix, dbg_prefix, level); 236bf215546Sopenharmony_ci return false; 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci if (target == GL_TEXTURE_CUBE_MAP) { 240bf215546Sopenharmony_ci int i; 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci assert(z < MAX_FACES); /* should have been caught earlier */ 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci /* make sure all the cube faces are present */ 245bf215546Sopenharmony_ci for (i = 0; i < depth; i++) { 246bf215546Sopenharmony_ci if (!texObj->Image[z+i][level]) { 247bf215546Sopenharmony_ci /* missing cube face */ 248bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 249bf215546Sopenharmony_ci "glCopyImageSubData(missing cube face)"); 250bf215546Sopenharmony_ci return false; 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci *tex_image = texObj->Image[z][level]; 255bf215546Sopenharmony_ci } 256bf215546Sopenharmony_ci else { 257bf215546Sopenharmony_ci *tex_image = _mesa_select_tex_image(texObj, target, level); 258bf215546Sopenharmony_ci } 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci if (!*tex_image) { 261bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 262bf215546Sopenharmony_ci "glCopyImageSubData%s(%sLevel = %u)", suffix, dbg_prefix, level); 263bf215546Sopenharmony_ci return false; 264bf215546Sopenharmony_ci } 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci *renderbuffer = NULL; 267bf215546Sopenharmony_ci *format = (*tex_image)->TexFormat; 268bf215546Sopenharmony_ci *internalFormat = (*tex_image)->InternalFormat; 269bf215546Sopenharmony_ci *width = (*tex_image)->Width; 270bf215546Sopenharmony_ci *height = (*tex_image)->Height; 271bf215546Sopenharmony_ci *num_samples = (*tex_image)->NumSamples; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci return true; 275bf215546Sopenharmony_ci} 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_cistatic void 278bf215546Sopenharmony_ciprepare_target(struct gl_context *ctx, GLuint name, GLenum target, 279bf215546Sopenharmony_ci int level, int z, 280bf215546Sopenharmony_ci struct gl_texture_image **texImage, 281bf215546Sopenharmony_ci struct gl_renderbuffer **renderbuffer) 282bf215546Sopenharmony_ci{ 283bf215546Sopenharmony_ci if (target == GL_RENDERBUFFER) { 284bf215546Sopenharmony_ci struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, name); 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci *renderbuffer = rb; 287bf215546Sopenharmony_ci *texImage = NULL; 288bf215546Sopenharmony_ci } else { 289bf215546Sopenharmony_ci struct gl_texture_object *texObj = _mesa_lookup_texture(ctx, name); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci if (target == GL_TEXTURE_CUBE_MAP) { 292bf215546Sopenharmony_ci *texImage = texObj->Image[z][level]; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci else { 295bf215546Sopenharmony_ci *texImage = _mesa_select_tex_image(texObj, target, level); 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci *renderbuffer = NULL; 299bf215546Sopenharmony_ci } 300bf215546Sopenharmony_ci} 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci/** 303bf215546Sopenharmony_ci * Check that the x,y,z,width,height,region is within the texture image 304bf215546Sopenharmony_ci * dimensions. 305bf215546Sopenharmony_ci * \return true if bounds OK, false if regions is out of bounds 306bf215546Sopenharmony_ci */ 307bf215546Sopenharmony_cistatic bool 308bf215546Sopenharmony_cicheck_region_bounds(struct gl_context *ctx, 309bf215546Sopenharmony_ci GLenum target, 310bf215546Sopenharmony_ci const struct gl_texture_image *tex_image, 311bf215546Sopenharmony_ci const struct gl_renderbuffer *renderbuffer, 312bf215546Sopenharmony_ci int x, int y, int z, int width, int height, int depth, 313bf215546Sopenharmony_ci const char *dbg_prefix, 314bf215546Sopenharmony_ci bool is_arb_version) 315bf215546Sopenharmony_ci{ 316bf215546Sopenharmony_ci int surfWidth, surfHeight, surfDepth; 317bf215546Sopenharmony_ci const char *suffix = is_arb_version ? "" : "NV"; 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci if (width < 0 || height < 0 || depth < 0) { 320bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 321bf215546Sopenharmony_ci "glCopyImageSubData%s(%sWidth, %sHeight, or %sDepth is negative)", 322bf215546Sopenharmony_ci suffix, dbg_prefix, dbg_prefix, dbg_prefix); 323bf215546Sopenharmony_ci return false; 324bf215546Sopenharmony_ci } 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci if (x < 0 || y < 0 || z < 0) { 327bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 328bf215546Sopenharmony_ci "glCopyImageSubData%s(%sX, %sY, or %sZ is negative)", 329bf215546Sopenharmony_ci suffix, dbg_prefix, dbg_prefix, dbg_prefix); 330bf215546Sopenharmony_ci return false; 331bf215546Sopenharmony_ci } 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci /* Check X direction */ 334bf215546Sopenharmony_ci if (target == GL_RENDERBUFFER) { 335bf215546Sopenharmony_ci surfWidth = renderbuffer->Width; 336bf215546Sopenharmony_ci } 337bf215546Sopenharmony_ci else { 338bf215546Sopenharmony_ci surfWidth = tex_image->Width; 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci if (x + width > surfWidth) { 342bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 343bf215546Sopenharmony_ci "glCopyImageSubData%s(%sX or %sWidth exceeds image bounds)", 344bf215546Sopenharmony_ci suffix, dbg_prefix, dbg_prefix); 345bf215546Sopenharmony_ci return false; 346bf215546Sopenharmony_ci } 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci /* Check Y direction */ 349bf215546Sopenharmony_ci switch (target) { 350bf215546Sopenharmony_ci case GL_RENDERBUFFER: 351bf215546Sopenharmony_ci surfHeight = renderbuffer->Height; 352bf215546Sopenharmony_ci break; 353bf215546Sopenharmony_ci case GL_TEXTURE_1D: 354bf215546Sopenharmony_ci case GL_TEXTURE_1D_ARRAY: 355bf215546Sopenharmony_ci surfHeight = 1; 356bf215546Sopenharmony_ci break; 357bf215546Sopenharmony_ci default: 358bf215546Sopenharmony_ci surfHeight = tex_image->Height; 359bf215546Sopenharmony_ci } 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci if (y + height > surfHeight) { 362bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 363bf215546Sopenharmony_ci "glCopyImageSubData%s(%sY or %sHeight exceeds image bounds)", 364bf215546Sopenharmony_ci suffix, dbg_prefix, dbg_prefix); 365bf215546Sopenharmony_ci return false; 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci 368bf215546Sopenharmony_ci /* Check Z direction */ 369bf215546Sopenharmony_ci switch (target) { 370bf215546Sopenharmony_ci case GL_RENDERBUFFER: 371bf215546Sopenharmony_ci case GL_TEXTURE_1D: 372bf215546Sopenharmony_ci case GL_TEXTURE_2D: 373bf215546Sopenharmony_ci case GL_TEXTURE_2D_MULTISAMPLE: 374bf215546Sopenharmony_ci case GL_TEXTURE_RECTANGLE: 375bf215546Sopenharmony_ci surfDepth = 1; 376bf215546Sopenharmony_ci break; 377bf215546Sopenharmony_ci case GL_TEXTURE_CUBE_MAP: 378bf215546Sopenharmony_ci surfDepth = 6; 379bf215546Sopenharmony_ci break; 380bf215546Sopenharmony_ci case GL_TEXTURE_1D_ARRAY: 381bf215546Sopenharmony_ci surfDepth = tex_image->Height; 382bf215546Sopenharmony_ci break; 383bf215546Sopenharmony_ci default: 384bf215546Sopenharmony_ci surfDepth = tex_image->Depth; 385bf215546Sopenharmony_ci } 386bf215546Sopenharmony_ci 387bf215546Sopenharmony_ci if (z < 0 || z + depth > surfDepth) { 388bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 389bf215546Sopenharmony_ci "glCopyImageSubData%s(%sZ or %sDepth exceeds image bounds)", 390bf215546Sopenharmony_ci suffix, dbg_prefix, dbg_prefix); 391bf215546Sopenharmony_ci return false; 392bf215546Sopenharmony_ci } 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci return true; 395bf215546Sopenharmony_ci} 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_cistatic bool 398bf215546Sopenharmony_cicompressed_format_compatible(const struct gl_context *ctx, 399bf215546Sopenharmony_ci GLenum compressedFormat, GLenum otherFormat) 400bf215546Sopenharmony_ci{ 401bf215546Sopenharmony_ci enum mesa_block_class compressedClass, otherClass; 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci /* Two view-incompatible compressed formats are never compatible. */ 404bf215546Sopenharmony_ci if (_mesa_is_compressed_format(ctx, otherFormat)) { 405bf215546Sopenharmony_ci return false; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci /* 409bf215546Sopenharmony_ci * From ARB_copy_image spec: 410bf215546Sopenharmony_ci * Table 4.X.1 (Compatible internal formats for copying between 411bf215546Sopenharmony_ci * compressed and uncompressed internal formats) 412bf215546Sopenharmony_ci * --------------------------------------------------------------------- 413bf215546Sopenharmony_ci * | Texel / | Uncompressed | | 414bf215546Sopenharmony_ci * | Block | internal format | Compressed internal format | 415bf215546Sopenharmony_ci * | size | | | 416bf215546Sopenharmony_ci * --------------------------------------------------------------------- 417bf215546Sopenharmony_ci * | 128-bit | RGBA32UI, | COMPRESSED_RGBA_S3TC_DXT3_EXT, | 418bf215546Sopenharmony_ci * | | RGBA32I, | COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,| 419bf215546Sopenharmony_ci * | | RGBA32F | COMPRESSED_RGBA_S3TC_DXT5_EXT, | 420bf215546Sopenharmony_ci * | | | COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,| 421bf215546Sopenharmony_ci * | | | COMPRESSED_RG_RGTC2, | 422bf215546Sopenharmony_ci * | | | COMPRESSED_SIGNED_RG_RGTC2, | 423bf215546Sopenharmony_ci * | | | COMPRESSED_RGBA_BPTC_UNORM, | 424bf215546Sopenharmony_ci * | | | COMPRESSED_SRGB_ALPHA_BPTC_UNORM, | 425bf215546Sopenharmony_ci * | | | COMPRESSED_RGB_BPTC_SIGNED_FLOAT, | 426bf215546Sopenharmony_ci * | | | COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT | 427bf215546Sopenharmony_ci * --------------------------------------------------------------------- 428bf215546Sopenharmony_ci * | 64-bit | RGBA16F, RG32F, | COMPRESSED_RGB_S3TC_DXT1_EXT, | 429bf215546Sopenharmony_ci * | | RGBA16UI, RG32UI, | COMPRESSED_SRGB_S3TC_DXT1_EXT, | 430bf215546Sopenharmony_ci * | | RGBA16I, RG32I, | COMPRESSED_RGBA_S3TC_DXT1_EXT, | 431bf215546Sopenharmony_ci * | | RGBA16, | COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,| 432bf215546Sopenharmony_ci * | | RGBA16_SNORM | COMPRESSED_RED_RGTC1, | 433bf215546Sopenharmony_ci * | | | COMPRESSED_SIGNED_RED_RGTC1 | 434bf215546Sopenharmony_ci * --------------------------------------------------------------------- 435bf215546Sopenharmony_ci */ 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci switch (compressedFormat) { 438bf215546Sopenharmony_ci case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: 439bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: 440bf215546Sopenharmony_ci case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: 441bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: 442bf215546Sopenharmony_ci case GL_COMPRESSED_RG_RGTC2: 443bf215546Sopenharmony_ci case GL_COMPRESSED_SIGNED_RG_RGTC2: 444bf215546Sopenharmony_ci case GL_COMPRESSED_RGBA_BPTC_UNORM: 445bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: 446bf215546Sopenharmony_ci case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: 447bf215546Sopenharmony_ci case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: 448bf215546Sopenharmony_ci compressedClass = BLOCK_CLASS_128_BITS; 449bf215546Sopenharmony_ci break; 450bf215546Sopenharmony_ci case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: 451bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: 452bf215546Sopenharmony_ci case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: 453bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: 454bf215546Sopenharmony_ci case GL_COMPRESSED_RED_RGTC1: 455bf215546Sopenharmony_ci case GL_COMPRESSED_SIGNED_RED_RGTC1: 456bf215546Sopenharmony_ci compressedClass = BLOCK_CLASS_64_BITS; 457bf215546Sopenharmony_ci break; 458bf215546Sopenharmony_ci case GL_COMPRESSED_RGBA8_ETC2_EAC: 459bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: 460bf215546Sopenharmony_ci case GL_COMPRESSED_RG11_EAC: 461bf215546Sopenharmony_ci case GL_COMPRESSED_SIGNED_RG11_EAC: 462bf215546Sopenharmony_ci if (_mesa_is_gles(ctx)) 463bf215546Sopenharmony_ci compressedClass = BLOCK_CLASS_128_BITS; 464bf215546Sopenharmony_ci else 465bf215546Sopenharmony_ci return false; 466bf215546Sopenharmony_ci break; 467bf215546Sopenharmony_ci case GL_COMPRESSED_RGB8_ETC2: 468bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB8_ETC2: 469bf215546Sopenharmony_ci case GL_COMPRESSED_R11_EAC: 470bf215546Sopenharmony_ci case GL_COMPRESSED_SIGNED_R11_EAC: 471bf215546Sopenharmony_ci case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: 472bf215546Sopenharmony_ci case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: 473bf215546Sopenharmony_ci if (_mesa_is_gles(ctx)) 474bf215546Sopenharmony_ci compressedClass = BLOCK_CLASS_64_BITS; 475bf215546Sopenharmony_ci else 476bf215546Sopenharmony_ci return false; 477bf215546Sopenharmony_ci break; 478bf215546Sopenharmony_ci default: 479bf215546Sopenharmony_ci if (_mesa_is_gles(ctx) && _mesa_is_astc_format(compressedFormat)) 480bf215546Sopenharmony_ci compressedClass = BLOCK_CLASS_128_BITS; 481bf215546Sopenharmony_ci else 482bf215546Sopenharmony_ci return false; 483bf215546Sopenharmony_ci break; 484bf215546Sopenharmony_ci } 485bf215546Sopenharmony_ci 486bf215546Sopenharmony_ci switch (otherFormat) { 487bf215546Sopenharmony_ci case GL_RGBA32UI: 488bf215546Sopenharmony_ci case GL_RGBA32I: 489bf215546Sopenharmony_ci case GL_RGBA32F: 490bf215546Sopenharmony_ci otherClass = BLOCK_CLASS_128_BITS; 491bf215546Sopenharmony_ci break; 492bf215546Sopenharmony_ci case GL_RGBA16F: 493bf215546Sopenharmony_ci case GL_RG32F: 494bf215546Sopenharmony_ci case GL_RGBA16UI: 495bf215546Sopenharmony_ci case GL_RG32UI: 496bf215546Sopenharmony_ci case GL_RGBA16I: 497bf215546Sopenharmony_ci case GL_RG32I: 498bf215546Sopenharmony_ci case GL_RGBA16: 499bf215546Sopenharmony_ci case GL_RGBA16_SNORM: 500bf215546Sopenharmony_ci otherClass = BLOCK_CLASS_64_BITS; 501bf215546Sopenharmony_ci break; 502bf215546Sopenharmony_ci default: 503bf215546Sopenharmony_ci return false; 504bf215546Sopenharmony_ci } 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci return compressedClass == otherClass; 507bf215546Sopenharmony_ci} 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_cistatic bool 510bf215546Sopenharmony_cicopy_format_compatible(const struct gl_context *ctx, 511bf215546Sopenharmony_ci GLenum srcFormat, GLenum dstFormat) 512bf215546Sopenharmony_ci{ 513bf215546Sopenharmony_ci /* 514bf215546Sopenharmony_ci * From ARB_copy_image spec: 515bf215546Sopenharmony_ci * For the purposes of CopyImageSubData, two internal formats 516bf215546Sopenharmony_ci * are considered compatible if any of the following conditions are 517bf215546Sopenharmony_ci * met: 518bf215546Sopenharmony_ci * * the formats are the same, 519bf215546Sopenharmony_ci * * the formats are considered compatible according to the 520bf215546Sopenharmony_ci * compatibility rules used for texture views as defined in 521bf215546Sopenharmony_ci * section 3.9.X. In particular, if both internal formats are listed 522bf215546Sopenharmony_ci * in the same entry of Table 3.X.2, they are considered compatible, or 523bf215546Sopenharmony_ci * * one format is compressed and the other is uncompressed and 524bf215546Sopenharmony_ci * Table 4.X.1 lists the two formats in the same row. 525bf215546Sopenharmony_ci */ 526bf215546Sopenharmony_ci 527bf215546Sopenharmony_ci if (_mesa_texture_view_compatible_format(ctx, srcFormat, dstFormat)) { 528bf215546Sopenharmony_ci /* Also checks if formats are equal. */ 529bf215546Sopenharmony_ci return true; 530bf215546Sopenharmony_ci } else if (_mesa_is_compressed_format(ctx, srcFormat)) { 531bf215546Sopenharmony_ci return compressed_format_compatible(ctx, srcFormat, dstFormat); 532bf215546Sopenharmony_ci } else if (_mesa_is_compressed_format(ctx, dstFormat)) { 533bf215546Sopenharmony_ci return compressed_format_compatible(ctx, dstFormat, srcFormat); 534bf215546Sopenharmony_ci } 535bf215546Sopenharmony_ci 536bf215546Sopenharmony_ci return false; 537bf215546Sopenharmony_ci} 538bf215546Sopenharmony_ci 539bf215546Sopenharmony_cistatic void 540bf215546Sopenharmony_cicopy_image_subdata(struct gl_context *ctx, 541bf215546Sopenharmony_ci struct gl_texture_image *srcTexImage, 542bf215546Sopenharmony_ci struct gl_renderbuffer *srcRenderbuffer, 543bf215546Sopenharmony_ci int srcX, int srcY, int srcZ, int srcLevel, 544bf215546Sopenharmony_ci struct gl_texture_image *dstTexImage, 545bf215546Sopenharmony_ci struct gl_renderbuffer *dstRenderbuffer, 546bf215546Sopenharmony_ci int dstX, int dstY, int dstZ, int dstLevel, 547bf215546Sopenharmony_ci int srcWidth, int srcHeight, int srcDepth) 548bf215546Sopenharmony_ci{ 549bf215546Sopenharmony_ci /* loop over 2D slices/faces/layers */ 550bf215546Sopenharmony_ci for (int i = 0; i < srcDepth; ++i) { 551bf215546Sopenharmony_ci int newSrcZ = srcZ + i; 552bf215546Sopenharmony_ci int newDstZ = dstZ + i; 553bf215546Sopenharmony_ci 554bf215546Sopenharmony_ci if (srcTexImage && 555bf215546Sopenharmony_ci srcTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { 556bf215546Sopenharmony_ci /* need to update srcTexImage pointer for the cube face */ 557bf215546Sopenharmony_ci assert(srcZ + i < MAX_FACES); 558bf215546Sopenharmony_ci srcTexImage = srcTexImage->TexObject->Image[srcZ + i][srcLevel]; 559bf215546Sopenharmony_ci assert(srcTexImage); 560bf215546Sopenharmony_ci newSrcZ = 0; 561bf215546Sopenharmony_ci } 562bf215546Sopenharmony_ci 563bf215546Sopenharmony_ci if (dstTexImage && 564bf215546Sopenharmony_ci dstTexImage->TexObject->Target == GL_TEXTURE_CUBE_MAP) { 565bf215546Sopenharmony_ci /* need to update dstTexImage pointer for the cube face */ 566bf215546Sopenharmony_ci assert(dstZ + i < MAX_FACES); 567bf215546Sopenharmony_ci dstTexImage = dstTexImage->TexObject->Image[dstZ + i][dstLevel]; 568bf215546Sopenharmony_ci assert(dstTexImage); 569bf215546Sopenharmony_ci newDstZ = 0; 570bf215546Sopenharmony_ci } 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_ci st_CopyImageSubData(ctx, 573bf215546Sopenharmony_ci srcTexImage, srcRenderbuffer, 574bf215546Sopenharmony_ci srcX, srcY, newSrcZ, 575bf215546Sopenharmony_ci dstTexImage, dstRenderbuffer, 576bf215546Sopenharmony_ci dstX, dstY, newDstZ, 577bf215546Sopenharmony_ci srcWidth, srcHeight); 578bf215546Sopenharmony_ci } 579bf215546Sopenharmony_ci} 580bf215546Sopenharmony_ci 581bf215546Sopenharmony_civoid GLAPIENTRY 582bf215546Sopenharmony_ci_mesa_CopyImageSubData_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel, 583bf215546Sopenharmony_ci GLint srcX, GLint srcY, GLint srcZ, 584bf215546Sopenharmony_ci GLuint dstName, GLenum dstTarget, GLint dstLevel, 585bf215546Sopenharmony_ci GLint dstX, GLint dstY, GLint dstZ, 586bf215546Sopenharmony_ci GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 587bf215546Sopenharmony_ci{ 588bf215546Sopenharmony_ci struct gl_texture_image *srcTexImage, *dstTexImage; 589bf215546Sopenharmony_ci struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 590bf215546Sopenharmony_ci 591bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage, 594bf215546Sopenharmony_ci &srcRenderbuffer); 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_ci prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage, 597bf215546Sopenharmony_ci &dstRenderbuffer); 598bf215546Sopenharmony_ci 599bf215546Sopenharmony_ci copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 600bf215546Sopenharmony_ci srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 601bf215546Sopenharmony_ci dstLevel, srcWidth, srcHeight, srcDepth); 602bf215546Sopenharmony_ci} 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_civoid GLAPIENTRY 605bf215546Sopenharmony_ci_mesa_CopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, 606bf215546Sopenharmony_ci GLint srcX, GLint srcY, GLint srcZ, 607bf215546Sopenharmony_ci GLuint dstName, GLenum dstTarget, GLint dstLevel, 608bf215546Sopenharmony_ci GLint dstX, GLint dstY, GLint dstZ, 609bf215546Sopenharmony_ci GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 610bf215546Sopenharmony_ci{ 611bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 612bf215546Sopenharmony_ci struct gl_texture_image *srcTexImage, *dstTexImage; 613bf215546Sopenharmony_ci struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 614bf215546Sopenharmony_ci mesa_format srcFormat, dstFormat; 615bf215546Sopenharmony_ci GLenum srcIntFormat, dstIntFormat; 616bf215546Sopenharmony_ci GLuint src_w, src_h, dst_w, dst_h; 617bf215546Sopenharmony_ci GLuint src_bw, src_bh, dst_bw, dst_bh; 618bf215546Sopenharmony_ci GLuint src_num_samples, dst_num_samples; 619bf215546Sopenharmony_ci int dstWidth, dstHeight, dstDepth; 620bf215546Sopenharmony_ci 621bf215546Sopenharmony_ci if (MESA_VERBOSE & VERBOSE_API) 622bf215546Sopenharmony_ci _mesa_debug(ctx, "glCopyImageSubData(%u, %s, %d, %d, %d, %d, " 623bf215546Sopenharmony_ci "%u, %s, %d, %d, %d, %d, " 624bf215546Sopenharmony_ci "%d, %d, %d)\n", 625bf215546Sopenharmony_ci srcName, _mesa_enum_to_string(srcTarget), srcLevel, 626bf215546Sopenharmony_ci srcX, srcY, srcZ, 627bf215546Sopenharmony_ci dstName, _mesa_enum_to_string(dstTarget), dstLevel, 628bf215546Sopenharmony_ci dstX, dstY, dstZ, 629bf215546Sopenharmony_ci srcWidth, srcHeight, srcDepth); 630bf215546Sopenharmony_ci 631bf215546Sopenharmony_ci if (!ctx->Extensions.ARB_copy_image) { 632bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 633bf215546Sopenharmony_ci "glCopyImageSubData(extension not available)"); 634bf215546Sopenharmony_ci return; 635bf215546Sopenharmony_ci } 636bf215546Sopenharmony_ci 637bf215546Sopenharmony_ci if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth, 638bf215546Sopenharmony_ci &srcTexImage, &srcRenderbuffer, &srcFormat, 639bf215546Sopenharmony_ci &srcIntFormat, &src_w, &src_h, &src_num_samples, 640bf215546Sopenharmony_ci "src",true)) 641bf215546Sopenharmony_ci return; 642bf215546Sopenharmony_ci 643bf215546Sopenharmony_ci if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth, 644bf215546Sopenharmony_ci &dstTexImage, &dstRenderbuffer, &dstFormat, 645bf215546Sopenharmony_ci &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, 646bf215546Sopenharmony_ci "dst",true)) 647bf215546Sopenharmony_ci return; 648bf215546Sopenharmony_ci 649bf215546Sopenharmony_ci _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh); 650bf215546Sopenharmony_ci 651bf215546Sopenharmony_ci /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile 652bf215546Sopenharmony_ci * spec says: 653bf215546Sopenharmony_ci * 654bf215546Sopenharmony_ci * An INVALID_VALUE error is generated if the dimensions of either 655bf215546Sopenharmony_ci * subregion exceeds the boundaries of the corresponding image object, 656bf215546Sopenharmony_ci * or if the image format is compressed and the dimensions of the 657bf215546Sopenharmony_ci * subregion fail to meet the alignment constraints of the format. 658bf215546Sopenharmony_ci * 659bf215546Sopenharmony_ci * and Section 8.7 (Compressed Texture Images) says: 660bf215546Sopenharmony_ci * 661bf215546Sopenharmony_ci * An INVALID_OPERATION error is generated if any of the following 662bf215546Sopenharmony_ci * conditions occurs: 663bf215546Sopenharmony_ci * 664bf215546Sopenharmony_ci * * width is not a multiple of four, and width + xoffset is not 665bf215546Sopenharmony_ci * equal to the value of TEXTURE_WIDTH. 666bf215546Sopenharmony_ci * * height is not a multiple of four, and height + yoffset is not 667bf215546Sopenharmony_ci * equal to the value of TEXTURE_HEIGHT. 668bf215546Sopenharmony_ci * 669bf215546Sopenharmony_ci * so we take that to mean that you can copy the "last" block of a 670bf215546Sopenharmony_ci * compressed texture image even if it's smaller than the minimum block 671bf215546Sopenharmony_ci * dimensions. 672bf215546Sopenharmony_ci */ 673bf215546Sopenharmony_ci if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || 674bf215546Sopenharmony_ci (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) || 675bf215546Sopenharmony_ci (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) { 676bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 677bf215546Sopenharmony_ci "glCopyImageSubData(unaligned src rectangle)"); 678bf215546Sopenharmony_ci return; 679bf215546Sopenharmony_ci } 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh); 682bf215546Sopenharmony_ci if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { 683bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 684bf215546Sopenharmony_ci "glCopyImageSubData(unaligned dst rectangle)"); 685bf215546Sopenharmony_ci return; 686bf215546Sopenharmony_ci } 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci /* From the GL_ARB_copy_image spec: 689bf215546Sopenharmony_ci * 690bf215546Sopenharmony_ci * "The dimensions are always specified in texels, even for compressed 691bf215546Sopenharmony_ci * texture formats. But it should be noted that if only one of the 692bf215546Sopenharmony_ci * source and destination textures is compressed then the number of 693bf215546Sopenharmony_ci * texels touched in the compressed image will be a factor of the 694bf215546Sopenharmony_ci * block size larger than in the uncompressed image." 695bf215546Sopenharmony_ci * 696bf215546Sopenharmony_ci * So, if copying from compressed to uncompressed, the dest region is 697bf215546Sopenharmony_ci * shrunk by the src block size factor. If copying from uncompressed 698bf215546Sopenharmony_ci * to compressed, the dest region is grown by the dest block size factor. 699bf215546Sopenharmony_ci * Note that we're passed the _source_ width, height, depth and those 700bf215546Sopenharmony_ci * dimensions are never changed. 701bf215546Sopenharmony_ci */ 702bf215546Sopenharmony_ci dstWidth = srcWidth * dst_bw / src_bw; 703bf215546Sopenharmony_ci dstHeight = srcHeight * dst_bh / src_bh; 704bf215546Sopenharmony_ci dstDepth = srcDepth; 705bf215546Sopenharmony_ci 706bf215546Sopenharmony_ci if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer, 707bf215546Sopenharmony_ci srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, 708bf215546Sopenharmony_ci "src", true)) 709bf215546Sopenharmony_ci return; 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer, 712bf215546Sopenharmony_ci dstX, dstY, dstZ, dstWidth, dstHeight, dstDepth, 713bf215546Sopenharmony_ci "dst", true)) 714bf215546Sopenharmony_ci return; 715bf215546Sopenharmony_ci 716bf215546Sopenharmony_ci /* Section 18.3.2 (Copying Between Images) of the OpenGL 4.5 Core Profile 717bf215546Sopenharmony_ci * spec says: 718bf215546Sopenharmony_ci * 719bf215546Sopenharmony_ci * An INVALID_OPERATION error is generated if either object is a texture 720bf215546Sopenharmony_ci * and the texture is not complete, if the source and destination internal 721bf215546Sopenharmony_ci * formats are not compatible, or if the number of samples do not match. 722bf215546Sopenharmony_ci */ 723bf215546Sopenharmony_ci if (!copy_format_compatible(ctx, srcIntFormat, dstIntFormat)) { 724bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 725bf215546Sopenharmony_ci "glCopyImageSubData(internalFormat mismatch)"); 726bf215546Sopenharmony_ci return; 727bf215546Sopenharmony_ci } 728bf215546Sopenharmony_ci 729bf215546Sopenharmony_ci if (src_num_samples != dst_num_samples) { 730bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 731bf215546Sopenharmony_ci "glCopyImageSubData(number of samples mismatch)"); 732bf215546Sopenharmony_ci return; 733bf215546Sopenharmony_ci } 734bf215546Sopenharmony_ci 735bf215546Sopenharmony_ci copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 736bf215546Sopenharmony_ci srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 737bf215546Sopenharmony_ci dstLevel, srcWidth, srcHeight, srcDepth); 738bf215546Sopenharmony_ci} 739bf215546Sopenharmony_ci 740bf215546Sopenharmony_civoid GLAPIENTRY 741bf215546Sopenharmony_ci_mesa_CopyImageSubDataNV_no_error(GLuint srcName, GLenum srcTarget, GLint srcLevel, 742bf215546Sopenharmony_ci GLint srcX, GLint srcY, GLint srcZ, 743bf215546Sopenharmony_ci GLuint dstName, GLenum dstTarget, GLint dstLevel, 744bf215546Sopenharmony_ci GLint dstX, GLint dstY, GLint dstZ, 745bf215546Sopenharmony_ci GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 746bf215546Sopenharmony_ci{ 747bf215546Sopenharmony_ci struct gl_texture_image *srcTexImage, *dstTexImage; 748bf215546Sopenharmony_ci struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 751bf215546Sopenharmony_ci 752bf215546Sopenharmony_ci prepare_target(ctx, srcName, srcTarget, srcLevel, srcZ, &srcTexImage, 753bf215546Sopenharmony_ci &srcRenderbuffer); 754bf215546Sopenharmony_ci 755bf215546Sopenharmony_ci prepare_target(ctx, dstName, dstTarget, dstLevel, dstZ, &dstTexImage, 756bf215546Sopenharmony_ci &dstRenderbuffer); 757bf215546Sopenharmony_ci 758bf215546Sopenharmony_ci copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 759bf215546Sopenharmony_ci srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 760bf215546Sopenharmony_ci dstLevel, srcWidth, srcHeight, srcDepth); 761bf215546Sopenharmony_ci} 762bf215546Sopenharmony_ci 763bf215546Sopenharmony_civoid GLAPIENTRY 764bf215546Sopenharmony_ci_mesa_CopyImageSubDataNV(GLuint srcName, GLenum srcTarget, GLint srcLevel, 765bf215546Sopenharmony_ci GLint srcX, GLint srcY, GLint srcZ, 766bf215546Sopenharmony_ci GLuint dstName, GLenum dstTarget, GLint dstLevel, 767bf215546Sopenharmony_ci GLint dstX, GLint dstY, GLint dstZ, 768bf215546Sopenharmony_ci GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth) 769bf215546Sopenharmony_ci{ 770bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 771bf215546Sopenharmony_ci struct gl_texture_image *srcTexImage, *dstTexImage; 772bf215546Sopenharmony_ci struct gl_renderbuffer *srcRenderbuffer, *dstRenderbuffer; 773bf215546Sopenharmony_ci mesa_format srcFormat, dstFormat; 774bf215546Sopenharmony_ci GLenum srcIntFormat, dstIntFormat; 775bf215546Sopenharmony_ci GLuint src_w, src_h, dst_w, dst_h; 776bf215546Sopenharmony_ci GLuint src_bw, src_bh, dst_bw, dst_bh; 777bf215546Sopenharmony_ci GLuint src_num_samples, dst_num_samples; 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci if (MESA_VERBOSE & VERBOSE_API) 780bf215546Sopenharmony_ci _mesa_debug(ctx, "glCopyImageSubDataNV(%u, %s, %d, %d, %d, %d, " 781bf215546Sopenharmony_ci "%u, %s, %d, %d, %d, %d, " 782bf215546Sopenharmony_ci "%d, %d, %d)\n", 783bf215546Sopenharmony_ci srcName, _mesa_enum_to_string(srcTarget), srcLevel, 784bf215546Sopenharmony_ci srcX, srcY, srcZ, 785bf215546Sopenharmony_ci dstName, _mesa_enum_to_string(dstTarget), dstLevel, 786bf215546Sopenharmony_ci dstX, dstY, dstZ, 787bf215546Sopenharmony_ci srcWidth, srcHeight, srcDepth); 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_ci if (!ctx->Extensions.NV_copy_image) { 790bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 791bf215546Sopenharmony_ci "glCopyImageSubDataNV(extension not available)"); 792bf215546Sopenharmony_ci return; 793bf215546Sopenharmony_ci } 794bf215546Sopenharmony_ci 795bf215546Sopenharmony_ci if (!prepare_target_err(ctx, srcName, srcTarget, srcLevel, srcZ, srcDepth, 796bf215546Sopenharmony_ci &srcTexImage, &srcRenderbuffer, &srcFormat, 797bf215546Sopenharmony_ci &srcIntFormat, &src_w, &src_h, &src_num_samples, 798bf215546Sopenharmony_ci "src", false)) 799bf215546Sopenharmony_ci return; 800bf215546Sopenharmony_ci 801bf215546Sopenharmony_ci if (!prepare_target_err(ctx, dstName, dstTarget, dstLevel, dstZ, srcDepth, 802bf215546Sopenharmony_ci &dstTexImage, &dstRenderbuffer, &dstFormat, 803bf215546Sopenharmony_ci &dstIntFormat, &dst_w, &dst_h, &dst_num_samples, 804bf215546Sopenharmony_ci "dst", false)) 805bf215546Sopenharmony_ci return; 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci /* 808bf215546Sopenharmony_ci * The NV_copy_image spec says: 809bf215546Sopenharmony_ci * 810bf215546Sopenharmony_ci * INVALID_OPERATION is generated if either object is a texture 811bf215546Sopenharmony_ci * and the texture is not consistent, or if the source and destination 812bf215546Sopenharmony_ci * internal formats or number of samples do not match. 813bf215546Sopenharmony_ci * 814bf215546Sopenharmony_ci * In the absence of any definition of texture consistency the texture 815bf215546Sopenharmony_ci * completeness check, which is affected in the prepare_target_err function, 816bf215546Sopenharmony_ci * is used instead in keeping with the ARB version. 817bf215546Sopenharmony_ci * The check related to the internal format here is different from the ARB 818bf215546Sopenharmony_ci * version which adds the ability to copy between images which have 819bf215546Sopenharmony_ci * different formats where the formats are compatible for texture views. 820bf215546Sopenharmony_ci */ 821bf215546Sopenharmony_ci if (srcIntFormat != dstIntFormat) { 822bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 823bf215546Sopenharmony_ci "glCopyImageSubDataNV(internalFormat mismatch)"); 824bf215546Sopenharmony_ci return; 825bf215546Sopenharmony_ci } 826bf215546Sopenharmony_ci 827bf215546Sopenharmony_ci if (src_num_samples != dst_num_samples) { 828bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 829bf215546Sopenharmony_ci "glCopyImageSubDataNV(number of samples mismatch)"); 830bf215546Sopenharmony_ci return; 831bf215546Sopenharmony_ci } 832bf215546Sopenharmony_ci 833bf215546Sopenharmony_ci /* 834bf215546Sopenharmony_ci * The NV_copy_image spec says: 835bf215546Sopenharmony_ci * 836bf215546Sopenharmony_ci * INVALID_VALUE is generated if the image format is compressed 837bf215546Sopenharmony_ci * and the dimensions of the subregion fail to meet the alignment 838bf215546Sopenharmony_ci * constraints of the format. 839bf215546Sopenharmony_ci * 840bf215546Sopenharmony_ci * The check here is identical to the ARB version. 841bf215546Sopenharmony_ci */ 842bf215546Sopenharmony_ci _mesa_get_format_block_size(srcFormat, &src_bw, &src_bh); 843bf215546Sopenharmony_ci if ((srcX % src_bw != 0) || (srcY % src_bh != 0) || 844bf215546Sopenharmony_ci (srcWidth % src_bw != 0 && (srcX + srcWidth) != src_w) || 845bf215546Sopenharmony_ci (srcHeight % src_bh != 0 && (srcY + srcHeight) != src_h)) { 846bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 847bf215546Sopenharmony_ci "glCopyImageSubDataNV(unaligned src rectangle)"); 848bf215546Sopenharmony_ci return; 849bf215546Sopenharmony_ci } 850bf215546Sopenharmony_ci 851bf215546Sopenharmony_ci _mesa_get_format_block_size(dstFormat, &dst_bw, &dst_bh); 852bf215546Sopenharmony_ci if ((dstX % dst_bw != 0) || (dstY % dst_bh != 0)) { 853bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 854bf215546Sopenharmony_ci "glCopyImageSubDataNV(unaligned dst rectangle)"); 855bf215546Sopenharmony_ci return; 856bf215546Sopenharmony_ci } 857bf215546Sopenharmony_ci 858bf215546Sopenharmony_ci /* 859bf215546Sopenharmony_ci * The NV_copy_image spec says: 860bf215546Sopenharmony_ci * 861bf215546Sopenharmony_ci * INVALID_VALUE is generated if the dimensions of the either subregion 862bf215546Sopenharmony_ci * exceeds the boundaries of the corresponding image object. 863bf215546Sopenharmony_ci * 864bf215546Sopenharmony_ci * The check here is similar to the ARB version except for the fact that 865bf215546Sopenharmony_ci * block sizes are not considered owing to the fact that copying across 866bf215546Sopenharmony_ci * compressed and uncompressed formats is not supported. 867bf215546Sopenharmony_ci */ 868bf215546Sopenharmony_ci if (!check_region_bounds(ctx, srcTarget, srcTexImage, srcRenderbuffer, 869bf215546Sopenharmony_ci srcX, srcY, srcZ, srcWidth, srcHeight, srcDepth, 870bf215546Sopenharmony_ci "src", false)) 871bf215546Sopenharmony_ci return; 872bf215546Sopenharmony_ci 873bf215546Sopenharmony_ci if (!check_region_bounds(ctx, dstTarget, dstTexImage, dstRenderbuffer, 874bf215546Sopenharmony_ci dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth, 875bf215546Sopenharmony_ci "dst", false)) 876bf215546Sopenharmony_ci return; 877bf215546Sopenharmony_ci 878bf215546Sopenharmony_ci copy_image_subdata(ctx, srcTexImage, srcRenderbuffer, srcX, srcY, srcZ, 879bf215546Sopenharmony_ci srcLevel, dstTexImage, dstRenderbuffer, dstX, dstY, dstZ, 880bf215546Sopenharmony_ci dstLevel, srcWidth, srcHeight, srcDepth); 881bf215546Sopenharmony_ci} 882