1 /*
2  * Copyright (C) 2009 Maciej Cencora <m.cencora@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 "radeon_common.h"
29 #include "radeon_texture.h"
30 
31 #include "main/enums.h"
32 #include "main/image.h"
33 #include "main/teximage.h"
34 #include "main/texstate.h"
35 #include "drivers/common/meta.h"
36 
37 #include "radeon_mipmap_tree.h"
38 
39 static GLboolean
do_copy_texsubimage(struct gl_context * ctx,struct radeon_tex_obj * tobj,radeon_texture_image * timg,GLint dstx,GLint dsty,struct radeon_renderbuffer * rrb,GLint x,GLint y,GLsizei width,GLsizei height)40 do_copy_texsubimage(struct gl_context *ctx,
41                     struct radeon_tex_obj *tobj,
42                     radeon_texture_image *timg,
43                     GLint dstx, GLint dsty,
44                     struct radeon_renderbuffer *rrb,
45                     GLint x, GLint y,
46                     GLsizei width, GLsizei height)
47 {
48     radeonContextPtr radeon = RADEON_CONTEXT(ctx);
49     const GLuint face = timg->base.Base.Face;
50     const GLuint level = timg->base.Base.Level;
51     unsigned src_bpp;
52     unsigned dst_bpp;
53     mesa_format src_mesaformat;
54     mesa_format dst_mesaformat;
55     unsigned flip_y;
56 
57     if (!radeon->vtbl.blit) {
58         return GL_FALSE;
59     }
60 
61     // This is software renderbuffer, fallback to swrast
62     if (!rrb) {
63         return GL_FALSE;
64     }
65 
66     if (_mesa_get_format_bits(timg->base.Base.TexFormat, GL_DEPTH_BITS) > 0) {
67         /* copying depth values */
68         flip_y = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Type == GL_NONE;
69     } else {
70         /* copying color */
71         flip_y = ctx->ReadBuffer->Attachment[BUFFER_COLOR0].Type == GL_NONE;
72     }
73 
74     if (!timg->mt) {
75         radeon_validate_texture_miptree(ctx, &tobj->base.Sampler, &tobj->base);
76     }
77 
78     assert(rrb->bo);
79     assert(timg->mt);
80     assert(timg->mt->bo);
81     assert(timg->base.Base.Width >= dstx + width);
82     assert(timg->base.Base.Height >= dsty + height);
83 
84     intptr_t src_offset = rrb->draw_offset;
85     intptr_t dst_offset = radeon_miptree_image_offset(timg->mt, face, level);
86 
87     if (0) {
88         fprintf(stderr, "%s: copying to face %d, level %d\n",
89                 __func__, face, level);
90         fprintf(stderr, "to: x %d, y %d, offset %d\n", dstx, dsty, (uint32_t) dst_offset);
91         fprintf(stderr, "from (%dx%d) width %d, height %d, offset %d, pitch %d\n",
92                 x, y, rrb->base.Base.Width, rrb->base.Base.Height, (uint32_t) src_offset, rrb->pitch/rrb->cpp);
93         fprintf(stderr, "src size %d, dst size %d\n", rrb->bo->size, timg->mt->bo->size);
94 
95     }
96 
97     src_mesaformat = rrb->base.Base.Format;
98     dst_mesaformat = timg->base.Base.TexFormat;
99     src_bpp = _mesa_get_format_bytes(src_mesaformat);
100     dst_bpp = _mesa_get_format_bytes(dst_mesaformat);
101     if (!radeon->vtbl.check_blit(dst_mesaformat, rrb->pitch / rrb->cpp)) {
102 	    /* depth formats tend to be special */
103 	    if (_mesa_get_format_bits(dst_mesaformat, GL_DEPTH_BITS) > 0)
104 		    return GL_FALSE;
105 
106 	    if (src_bpp != dst_bpp)
107 		    return GL_FALSE;
108 
109 	    switch (dst_bpp) {
110 	    case 2:
111 		    src_mesaformat = MESA_FORMAT_B5G6R5_UNORM;
112 		    dst_mesaformat = MESA_FORMAT_B5G6R5_UNORM;
113 		    break;
114 	    case 4:
115 		    src_mesaformat = MESA_FORMAT_B8G8R8A8_UNORM;
116 		    dst_mesaformat = MESA_FORMAT_B8G8R8A8_UNORM;
117 		    break;
118 	    case 1:
119 		    src_mesaformat = MESA_FORMAT_A_UNORM8;
120 		    dst_mesaformat = MESA_FORMAT_A_UNORM8;
121 		    break;
122 	    default:
123 		    return GL_FALSE;
124 	    }
125     }
126 
127     /* blit from src buffer to texture */
128     return radeon->vtbl.blit(ctx, rrb->bo, src_offset, src_mesaformat, rrb->pitch/rrb->cpp,
129                              rrb->base.Base.Width, rrb->base.Base.Height, x, y,
130                              timg->mt->bo, dst_offset, dst_mesaformat,
131                              timg->mt->levels[level].rowstride / dst_bpp,
132                              timg->base.Base.Width, timg->base.Base.Height,
133                              dstx, dsty, width, height, flip_y);
134 }
135 
136 void
radeonCopyTexSubImage(struct gl_context * ctx,GLuint dims,struct gl_texture_image * texImage,GLint xoffset,GLint yoffset,GLint slice,struct gl_renderbuffer * rb,GLint x,GLint y,GLsizei width,GLsizei height)137 radeonCopyTexSubImage(struct gl_context *ctx, GLuint dims,
138                       struct gl_texture_image *texImage,
139                       GLint xoffset, GLint yoffset, GLint slice,
140                       struct gl_renderbuffer *rb,
141                       GLint x, GLint y,
142                       GLsizei width, GLsizei height)
143 {
144     radeonContextPtr radeon = RADEON_CONTEXT(ctx);
145     radeon_prepare_render(radeon);
146 
147     if (slice != 0 || !do_copy_texsubimage(ctx,
148                              radeon_tex_obj(texImage->TexObject),
149                              (radeon_texture_image *)texImage,
150                              xoffset, yoffset,
151                              radeon_renderbuffer(rb),                                                        x, y, width, height)) {
152 
153         radeon_print(RADEON_FALLBACKS, RADEON_NORMAL,
154                      "Falling back to sw for glCopyTexSubImage2D\n");
155 
156         _mesa_meta_CopyTexSubImage(ctx, dims, texImage,
157                                    xoffset, yoffset, slice,
158                                      rb, x, y, width, height);
159     }
160 }
161