Home | History | Annotate | Download | only in radeon
      1 /*
      2  * Copyright (C) 2010 Maciej Cencora <m.cencora (at) gmail.com>
      3  *
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining
      7  * a copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sublicense, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial
     16  * portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     21  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
     22  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     23  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  */
     27 
     28 #include "stdint.h"
     29 #include "main/bufferobj.h"
     30 #include "main/enums.h"
     31 #include "main/fbobject.h"
     32 #include "main/image.h"
     33 #include "main/readpix.h"
     34 #include "main/state.h"
     35 
     36 #include "radeon_common_context.h"
     37 #include "radeon_buffer_objects.h"
     38 #include "radeon_debug.h"
     39 #include "radeon_mipmap_tree.h"
     40 
     41 static mesa_format gl_format_and_type_to_mesa_format(GLenum format, GLenum type)
     42 {
     43     switch (format)
     44     {
     45         case GL_RGB:
     46             switch (type) {
     47                 case GL_UNSIGNED_SHORT_5_6_5:
     48                     return MESA_FORMAT_B5G6R5_UNORM;
     49                 case GL_UNSIGNED_SHORT_5_6_5_REV:
     50                     return MESA_FORMAT_R5G6B5_UNORM;
     51             }
     52             break;
     53         case GL_RGBA:
     54             switch (type) {
     55                 case GL_FLOAT:
     56                     return MESA_FORMAT_RGBA_FLOAT32;
     57                 case GL_UNSIGNED_SHORT_5_5_5_1:
     58                     return MESA_FORMAT_A1B5G5R5_UNORM;
     59                 case GL_UNSIGNED_INT_8_8_8_8:
     60                     return MESA_FORMAT_A8B8G8R8_UNORM;
     61                 case GL_UNSIGNED_BYTE:
     62                 case GL_UNSIGNED_INT_8_8_8_8_REV:
     63                     return MESA_FORMAT_R8G8B8A8_UNORM;
     64             }
     65             break;
     66         case GL_BGRA:
     67             switch (type) {
     68                 case GL_UNSIGNED_SHORT_4_4_4_4:
     69                     return MESA_FORMAT_A4R4G4B4_UNORM;
     70                 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
     71                     return MESA_FORMAT_B4G4R4A4_UNORM;
     72                 case GL_UNSIGNED_SHORT_5_5_5_1:
     73                     return MESA_FORMAT_A1R5G5B5_UNORM;
     74                 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
     75                     return MESA_FORMAT_B5G5R5A1_UNORM;
     76                 case GL_UNSIGNED_INT_8_8_8_8:
     77                     return MESA_FORMAT_A8R8G8B8_UNORM;
     78                 case GL_UNSIGNED_BYTE:
     79                 case GL_UNSIGNED_INT_8_8_8_8_REV:
     80                     return MESA_FORMAT_B8G8R8A8_UNORM;
     81 
     82             }
     83             break;
     84     }
     85 
     86     return MESA_FORMAT_NONE;
     87 }
     88 
     89 static GLboolean
     90 do_blit_readpixels(struct gl_context * ctx,
     91                    GLint x, GLint y, GLsizei width, GLsizei height,
     92                    GLenum format, GLenum type,
     93                    const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
     94 {
     95     radeonContextPtr radeon = RADEON_CONTEXT(ctx);
     96     const struct radeon_renderbuffer *rrb = radeon_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
     97     const mesa_format dst_format = gl_format_and_type_to_mesa_format(format, type);
     98     unsigned dst_rowstride, dst_imagesize, aligned_rowstride, flip_y;
     99     struct radeon_bo *dst_buffer;
    100     GLint dst_x = 0, dst_y = 0;
    101     intptr_t dst_offset;
    102 
    103     /* It's not worth if number of pixels to copy is really small */
    104     if (width * height < 100) {
    105         return GL_FALSE;
    106     }
    107 
    108     if (dst_format == MESA_FORMAT_NONE ||
    109         !radeon->vtbl.check_blit(dst_format, rrb->pitch / rrb->cpp) || !radeon->vtbl.blit) {
    110         return GL_FALSE;
    111     }
    112 
    113     if (ctx->_ImageTransferState || ctx->Color.ColorLogicOpEnabled) {
    114         return GL_FALSE;
    115     }
    116 
    117     if (pack->SwapBytes || pack->LsbFirst) {
    118         return GL_FALSE;
    119     }
    120 
    121     if (pack->RowLength > 0) {
    122         dst_rowstride = pack->RowLength;
    123     } else {
    124         dst_rowstride = width;
    125     }
    126 
    127     if (!_mesa_clip_copytexsubimage(ctx, &dst_x, &dst_y, &x, &y, &width, &height)) {
    128         return GL_TRUE;
    129     }
    130     assert(x >= 0 && y >= 0);
    131 
    132     aligned_rowstride = get_texture_image_row_stride(radeon, dst_format, dst_rowstride, 0, GL_TEXTURE_2D);
    133     dst_rowstride *= _mesa_get_format_bytes(dst_format);
    134     if (_mesa_is_bufferobj(pack->BufferObj) && aligned_rowstride != dst_rowstride)
    135         return GL_FALSE;
    136     dst_imagesize = get_texture_image_size(dst_format,
    137                                            aligned_rowstride,
    138                                            height, 1, 0);
    139 
    140     if (!_mesa_is_bufferobj(pack->BufferObj))
    141     {
    142         dst_buffer = radeon_bo_open(radeon->radeonScreen->bom, 0, dst_imagesize, 1024, RADEON_GEM_DOMAIN_GTT, 0);
    143         dst_offset = 0;
    144     }
    145     else
    146     {
    147         dst_buffer = get_radeon_buffer_object(pack->BufferObj)->bo;
    148         dst_offset = (intptr_t)pixels;
    149     }
    150 
    151     /* Disable source Y flipping for FBOs */
    152     flip_y = _mesa_is_winsys_fbo(ctx->ReadBuffer);
    153     if (pack->Invert) {
    154         y = rrb->base.Base.Height - height - y;
    155         flip_y = !flip_y;
    156     }
    157 
    158     if (radeon->vtbl.blit(ctx,
    159                           rrb->bo,
    160                           rrb->draw_offset,
    161                           rrb->base.Base.Format,
    162                           rrb->pitch / rrb->cpp,
    163                           rrb->base.Base.Width,
    164                           rrb->base.Base.Height,
    165                           x,
    166                           y,
    167                           dst_buffer,
    168                           dst_offset,
    169                           dst_format,
    170                           aligned_rowstride / _mesa_get_format_bytes(dst_format),
    171                           width,
    172                           height,
    173                           0, /* dst_x */
    174                           0, /* dst_y */
    175                           width,
    176                           height,
    177                           flip_y))
    178     {
    179         if (!_mesa_is_bufferobj(pack->BufferObj))
    180         {
    181             radeon_bo_map(dst_buffer, 0);
    182             copy_rows(pixels, dst_rowstride, dst_buffer->ptr,
    183                       aligned_rowstride, height, dst_rowstride);
    184             radeon_bo_unmap(dst_buffer);
    185             radeon_bo_unref(dst_buffer);
    186         }
    187 
    188         return GL_TRUE;
    189     }
    190 
    191     if (!_mesa_is_bufferobj(pack->BufferObj))
    192         radeon_bo_unref(dst_buffer);
    193 
    194     return GL_FALSE;
    195 }
    196 
    197 void
    198 radeonReadPixels(struct gl_context * ctx,
    199                  GLint x, GLint y, GLsizei width, GLsizei height,
    200                  GLenum format, GLenum type,
    201                  const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
    202 {
    203     radeonContextPtr radeon = RADEON_CONTEXT(ctx);
    204     radeon_prepare_render(radeon);
    205 
    206     if (do_blit_readpixels(ctx, x, y, width, height, format, type, pack, pixels))
    207         return;
    208 
    209     /* Update Mesa state before calling _mesa_readpixels().
    210      * XXX this may not be needed since ReadPixels no longer uses the
    211      * span code.
    212      */
    213     radeon_print(RADEON_FALLBACKS, RADEON_NORMAL,
    214                  "Falling back to sw for ReadPixels (format %s, type %s)\n",
    215                  _mesa_enum_to_string(format), _mesa_enum_to_string(type));
    216 
    217     if (ctx->NewState)
    218         _mesa_update_state(ctx);
    219 
    220     _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels);
    221 }
    222