1/*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 *    Neil Roberts <neil@linux.intel.com>
25 */
26
27/** @file brw_conditional_render.c
28 *
29 * Support for conditional rendering based on query objects
30 * (GL_NV_conditional_render, GL_ARB_conditional_render_inverted) on Gfx7+.
31 */
32
33#include "main/condrender.h"
34
35#include "brw_context.h"
36#include "brw_defines.h"
37#include "brw_batch.h"
38
39static void
40set_predicate_enable(struct brw_context *brw,
41                     bool value)
42{
43   if (value)
44      brw->predicate.state = BRW_PREDICATE_STATE_RENDER;
45   else
46      brw->predicate.state = BRW_PREDICATE_STATE_DONT_RENDER;
47}
48
49static void
50set_predicate_for_overflow_query(struct brw_context *brw,
51                                 struct brw_query_object *query,
52                                 int stream_start, int count)
53{
54   if (!can_do_mi_math_and_lrr(brw->screen)) {
55      brw->predicate.state = BRW_PREDICATE_STATE_STALL_FOR_QUERY;
56      return;
57   }
58
59   brw->predicate.state = BRW_PREDICATE_STATE_USE_BIT;
60
61   /* Needed to ensure the memory is coherent for the MI_LOAD_REGISTER_MEM
62    * command when loading the values into the predicate source registers for
63    * conditional rendering.
64    */
65   brw_emit_pipe_control_flush(brw, PIPE_CONTROL_FLUSH_ENABLE);
66
67   hsw_overflow_result_to_gpr0(brw, query, count);
68   brw_load_register_reg64(brw, MI_PREDICATE_SRC0, HSW_CS_GPR(0));
69   brw_load_register_imm64(brw, MI_PREDICATE_SRC1, 0ull);
70}
71
72static void
73set_predicate_for_occlusion_query(struct brw_context *brw,
74                                  struct brw_query_object *query)
75{
76   if (!brw->predicate.supported) {
77      brw->predicate.state = BRW_PREDICATE_STATE_STALL_FOR_QUERY;
78      return;
79   }
80
81   brw->predicate.state = BRW_PREDICATE_STATE_USE_BIT;
82
83   /* Needed to ensure the memory is coherent for the MI_LOAD_REGISTER_MEM
84    * command when loading the values into the predicate source registers for
85    * conditional rendering.
86    */
87   brw_emit_pipe_control_flush(brw, PIPE_CONTROL_FLUSH_ENABLE);
88
89   brw_load_register_mem64(brw, MI_PREDICATE_SRC0, query->bo, 0 /* offset */);
90   brw_load_register_mem64(brw, MI_PREDICATE_SRC1, query->bo, 8 /* offset */);
91}
92
93static void
94set_predicate_for_result(struct brw_context *brw,
95                         struct brw_query_object *query,
96                         bool inverted)
97{
98   int load_op;
99
100   assert(query->bo != NULL);
101
102   switch (query->Base.Target) {
103   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
104      set_predicate_for_overflow_query(brw, query, 0, 1);
105      break;
106   case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
107      set_predicate_for_overflow_query(brw, query, 0, MAX_VERTEX_STREAMS);
108      break;
109   default:
110      set_predicate_for_occlusion_query(brw, query);
111   }
112
113   if (brw->predicate.state == BRW_PREDICATE_STATE_USE_BIT) {
114      if (inverted)
115         load_op = MI_PREDICATE_LOADOP_LOAD;
116      else
117         load_op = MI_PREDICATE_LOADOP_LOADINV;
118
119      BEGIN_BATCH(1);
120      OUT_BATCH(GFX7_MI_PREDICATE |
121                load_op |
122                MI_PREDICATE_COMBINEOP_SET |
123                MI_PREDICATE_COMPAREOP_SRCS_EQUAL);
124      ADVANCE_BATCH();
125   }
126}
127
128static void
129brw_begin_conditional_render(struct gl_context *ctx,
130                             struct gl_query_object *q,
131                             GLenum mode)
132{
133   struct brw_context *brw = brw_context(ctx);
134   struct brw_query_object *query = (struct brw_query_object *) q;
135   bool inverted;
136
137   switch (mode) {
138   case GL_QUERY_WAIT:
139   case GL_QUERY_NO_WAIT:
140   case GL_QUERY_BY_REGION_WAIT:
141   case GL_QUERY_BY_REGION_NO_WAIT:
142      inverted = false;
143      break;
144   case GL_QUERY_WAIT_INVERTED:
145   case GL_QUERY_NO_WAIT_INVERTED:
146   case GL_QUERY_BY_REGION_WAIT_INVERTED:
147   case GL_QUERY_BY_REGION_NO_WAIT_INVERTED:
148      inverted = true;
149      break;
150   default:
151      unreachable("Unexpected conditional render mode");
152   }
153
154   /* If there are already samples from a BLT operation or if the query object
155    * is ready then we can avoid looking at the values in the buffer and just
156    * decide whether to draw using the CPU without stalling.
157    */
158   if (query->Base.Result || query->Base.Ready)
159      set_predicate_enable(brw, (query->Base.Result != 0) ^ inverted);
160   else
161      set_predicate_for_result(brw, query, inverted);
162}
163
164static void
165brw_end_conditional_render(struct gl_context *ctx,
166                           struct gl_query_object *q)
167{
168   struct brw_context *brw = brw_context(ctx);
169
170   /* When there is no longer a conditional render in progress it should
171    * always render.
172    */
173   brw->predicate.state = BRW_PREDICATE_STATE_RENDER;
174}
175
176void
177brw_init_conditional_render_functions(struct dd_function_table *functions)
178{
179   functions->BeginConditionalRender = brw_begin_conditional_render;
180   functions->EndConditionalRender = brw_end_conditional_render;
181}
182
183bool
184brw_check_conditional_render(struct brw_context *brw)
185{
186   if (brw->predicate.state == BRW_PREDICATE_STATE_STALL_FOR_QUERY) {
187      perf_debug("Conditional rendering is implemented in software and may "
188                 "stall.\n");
189      return _mesa_check_conditional_render(&brw->ctx);
190   }
191
192   return brw->predicate.state != BRW_PREDICATE_STATE_DONT_RENDER;
193}
194