summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i965/brw_meta_util.c
blob: a3b060413e504fd5bf4808b3c733e64c585f8e50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Copyright © 2014 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "brw_meta_util.h"
#include "main/fbobject.h"

/**
 * Helper function for handling mirror image blits.
 *
 * If coord0 > coord1, swap them and invert the "mirror" boolean.
 */
static inline void
fixup_mirroring(bool *mirror, float *coord0, float *coord1)
{
   if (*coord0 > *coord1) {
      *mirror = !*mirror;
      float tmp = *coord0;
      *coord0 = *coord1;
      *coord1 = tmp;
   }
}

/**
 * Adjust {src,dst}_x{0,1} to account for clipping and scissoring of
 * destination coordinates.
 *
 * Return true if there is still blitting to do, false if all pixels got
 * rejected by the clip and/or scissor.
 *
 * For clarity, the nomenclature of this function assumes we are clipping and
 * scissoring the X coordinate; the exact same logic applies for Y
 * coordinates.
 *
 * Note: this function may also be used to account for clipping of source
 * coordinates, by swapping the roles of src and dst.
 */
static inline bool
clip_or_scissor(bool mirror,
                GLfloat *src_x0, GLfloat *src_x1,
                GLfloat *dst_x0, GLfloat *dst_x1,
                GLfloat fb_xmin, GLfloat fb_xmax)
{
   float scale = (float) (*src_x1 - *src_x0) / (*dst_x1 - *dst_x0);
   /* If we are going to scissor everything away, stop. */
   if (!(fb_xmin < fb_xmax &&
         *dst_x0 < fb_xmax &&
         fb_xmin < *dst_x1 &&
         *dst_x0 < *dst_x1)) {
      return false;
   }

   /* Clip the destination rectangle, and keep track of how many pixels we
    * clipped off of the left and right sides of it.
    */
   int pixels_clipped_left = 0;
   int pixels_clipped_right = 0;
   if (*dst_x0 < fb_xmin) {
      pixels_clipped_left = fb_xmin - *dst_x0;
      *dst_x0 = fb_xmin;
   }
   if (fb_xmax < *dst_x1) {
      pixels_clipped_right = *dst_x1 - fb_xmax;
      *dst_x1 = fb_xmax;
   }

   /* If we are mirrored, then before applying pixels_clipped_{left,right} to
    * the source coordinates, we need to flip them to account for the
    * mirroring.
    */
   if (mirror) {
      int tmp = pixels_clipped_left;
      pixels_clipped_left = pixels_clipped_right;
      pixels_clipped_right = tmp;
   }

   /* Adjust the source rectangle to remove the pixels corresponding to those
    * that were clipped/scissored out of the destination rectangle.
    */
   *src_x0 += pixels_clipped_left * scale;
   *src_x1 -= pixels_clipped_right * scale;

   return true;
}

bool
brw_meta_mirror_clip_and_scissor(const struct gl_context *ctx,
                                 const struct gl_framebuffer *read_fb,
                                 const struct gl_framebuffer *draw_fb,
                                 GLfloat *srcX0, GLfloat *srcY0,
                                 GLfloat *srcX1, GLfloat *srcY1,
                                 GLfloat *dstX0, GLfloat *dstY0,
                                 GLfloat *dstX1, GLfloat *dstY1,
                                 bool *mirror_x, bool *mirror_y)
{
   *mirror_x = false;
   *mirror_y = false;

   /* Detect if the blit needs to be mirrored */
   fixup_mirroring(mirror_x, srcX0, srcX1);
   fixup_mirroring(mirror_x, dstX0, dstX1);
   fixup_mirroring(mirror_y, srcY0, srcY1);
   fixup_mirroring(mirror_y, dstY0, dstY1);

   /* If the destination rectangle needs to be clipped or scissored, do so. */
   if (!(clip_or_scissor(*mirror_x, srcX0, srcX1, dstX0, dstX1,
                         draw_fb->_Xmin, draw_fb->_Xmax) &&
         clip_or_scissor(*mirror_y, srcY0, srcY1, dstY0, dstY1,
                         draw_fb->_Ymin, draw_fb->_Ymax))) {
      /* Everything got clipped/scissored away, so the blit was successful. */
      return true;
   }

   /* If the source rectangle needs to be clipped or scissored, do so. */
   if (!(clip_or_scissor(*mirror_x, dstX0, dstX1, srcX0, srcX1,
                         0, read_fb->Width) &&
         clip_or_scissor(*mirror_y, dstY0, dstY1, srcY0, srcY1,
                         0, read_fb->Height))) {
      /* Everything got clipped/scissored away, so the blit was successful. */
      return true;
   }

   /* Account for the fact that in the system framebuffer, the origin is at
    * the lower left.
    */
   if (_mesa_is_winsys_fbo(read_fb)) {
      GLint tmp = read_fb->Height - *srcY0;
      *srcY0 = read_fb->Height - *srcY1;
      *srcY1 = tmp;
      *mirror_y = !*mirror_y;
   }
   if (_mesa_is_winsys_fbo(draw_fb)) {
      GLint tmp = draw_fb->Height - *dstY0;
      *dstY0 = draw_fb->Height - *dstY1;
      *dstY1 = tmp;
      *mirror_y = !*mirror_y;
   }

   return false;
}