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 Gen7+.
31  */
32 
33 #include "main/condrender.h"
34 
35 #include "brw_context.h"
36 #include "brw_defines.h"
37 #include "intel_batchbuffer.h"
38 
39 static void
set_predicate_enable(struct brw_context * brw,bool value)40 set_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 
49 static void
set_predicate_for_overflow_query(struct brw_context * brw,struct brw_query_object * query,int stream_start,int count)50 set_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 
72 static void
set_predicate_for_occlusion_query(struct brw_context * brw,struct brw_query_object * query)73 set_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 
93 static void
set_predicate_for_result(struct brw_context * brw,struct brw_query_object * query,bool inverted)94 set_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(GEN7_MI_PREDICATE |
121                 load_op |
122                 MI_PREDICATE_COMBINEOP_SET |
123                 MI_PREDICATE_COMPAREOP_SRCS_EQUAL);
124       ADVANCE_BATCH();
125    }
126 }
127 
128 static void
brw_begin_conditional_render(struct gl_context * ctx,struct gl_query_object * q,GLenum mode)129 brw_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 
164 static void
brw_end_conditional_render(struct gl_context * ctx,struct gl_query_object * q)165 brw_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 
176 void
brw_init_conditional_render_functions(struct dd_function_table * functions)177 brw_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 
183 bool
brw_check_conditional_render(struct brw_context * brw)184 brw_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