brw_queryobj.c revision c4c78c275abffe8d1014b1355f02239859d6aa2b
1c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/* 2c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Copyright © 2008 Intel Corporation 3c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 4c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Permission is hereby granted, free of charge, to any person obtaining a 5c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * copy of this software and associated documentation files (the "Software"), 6c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * to deal in the Software without restriction, including without limitation 7c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * and/or sell copies of the Software, and to permit persons to whom the 9c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Software is furnished to do so, subject to the following conditions: 10c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 11c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * The above copyright notice and this permission notice (including the next 12c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * paragraph) shall be included in all copies or substantial portions of the 13c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Software. 14c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 15c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * IN THE SOFTWARE. 22c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 23c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Authors: 24c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Eric Anholt <eric@anholt.net> 25c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 26c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt */ 27c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 28c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** @file support for ARB_query_object 29c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 30c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * ARB_query_object is implemented by using the PIPE_CONTROL command to stall 31c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * execution on the completion of previous depth tests, and write the 32c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * current PS_DEPTH_COUNT to a buffer object. 33c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * 34c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * We use before and after counts when drawing during a query so that 35c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * we don't pick up other clients' query data in ours. To reduce overhead, 36c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * a single BO is used to record the query data for all active queries at 37c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * once. This also gives us a simple bound on how much batchbuffer space is 38c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * required for handling queries, so that we can be sure that we won't 39c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * have to emit a batchbuffer without getting the ending PS_DEPTH_COUNT. 40c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt */ 41c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt#include "main/imports.h" 42c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 43c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt#include "brw_context.h" 4459b2c2adbbece27ccf54e58b598ea29cb3a5aa85Eric Anholt#include "brw_state.h" 45c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt#include "intel_batchbuffer.h" 46c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt#include "intel_reg.h" 47c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 4803f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunkestatic void 4903f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunkewrite_timestamp(struct intel_context *intel, drm_intel_bo *query_bo, int idx) 5003f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke{ 5103f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke if (intel->gen >= 6) { 52c4c78c275abffe8d1014b1355f02239859d6aa2bKenneth Graunke BEGIN_BATCH(5); 53c4c78c275abffe8d1014b1355f02239859d6aa2bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (5 - 2)); 5403f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_BATCH(PIPE_CONTROL_WRITE_TIMESTAMP); 5503f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_RELOC(query_bo, 5603f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 5703f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke PIPE_CONTROL_GLOBAL_GTT_WRITE | 5803f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke idx * sizeof(uint64_t)); 5903f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_BATCH(0); 60c4c78c275abffe8d1014b1355f02239859d6aa2bKenneth Graunke OUT_BATCH(0); 6103f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke ADVANCE_BATCH(); 6203f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke } else { 6303f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke BEGIN_BATCH(4); 6403f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2) | 6503f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke PIPE_CONTROL_WRITE_TIMESTAMP); 6603f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_RELOC(query_bo, 6703f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 6803f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke PIPE_CONTROL_GLOBAL_GTT_WRITE | 6903f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke idx * sizeof(uint64_t)); 7003f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_BATCH(0); 7103f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke OUT_BATCH(0); 7203f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke ADVANCE_BATCH(); 7303f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke } 7403f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke} 7503f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke 76c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** Waits on the query object's BO and totals the results for this query */ 77c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtstatic void 787457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan haibrw_queryobj_get_results(struct gl_context *ctx, 797457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai struct brw_query_object *query) 80c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 817457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai struct intel_context *intel = intel_context(ctx); 827457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai 83c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt int i; 84c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt uint64_t *results; 85c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 86c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt if (query->bo == NULL) 87c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt return; 88c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 892e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke drm_intel_bo_map(query->bo, false); 90c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt results = query->bo->virtual; 91c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry switch (query->Base.Target) { 92c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_TIME_ELAPSED_EXT: 937457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai if (intel->gen >= 6) 947457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai query->Base.Result += 80 * (results[1] - results[0]); 957457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai else 967457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai query->Base.Result += 1000 * ((results[1] >> 32) - (results[0] >> 32)); 97c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 98c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 99c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_SAMPLES_PASSED_ARB: 1003b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt /* Map and count the pixels from the current query BO */ 1013b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt for (i = query->first_index; i <= query->last_index; i++) { 1023b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt query->Base.Result += results[i * 2 + 1] - results[i * 2]; 1033b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt } 104c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 105c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 106c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_PRIMITIVES_GENERATED: 107c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 108c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* We don't actually query the hardware for this value, so query->bo 109c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * should always be NULL and execution should never reach here. 110c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 111c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry assert(!"Unreachable"); 112c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry break; 113c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 114c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry default: 115c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry assert(!"Unrecognized query target in brw_queryobj_get_results()"); 116c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 117c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt } 11834474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unmap(query->bo); 119c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 12034474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(query->bo); 121c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt query->bo = NULL; 122c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 123c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 124c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtstatic struct gl_query_object * 125f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergbrw_new_query_object(struct gl_context *ctx, GLuint id) 126c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 127c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query; 128c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 12932f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg query = calloc(1, sizeof(struct brw_query_object)); 130c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 131c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt query->Base.Id = id; 132c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt query->Base.Result = 0; 1332e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke query->Base.Active = false; 1342e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke query->Base.Ready = true; 135c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 136c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt return &query->Base; 137c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 138c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 139c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtstatic void 140f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergbrw_delete_query(struct gl_context *ctx, struct gl_query_object *q) 141c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 142c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query = (struct brw_query_object *)q; 143c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 14434474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(query->bo); 14532f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg free(query); 146c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 147c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 148c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtstatic void 149f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergbrw_begin_query(struct gl_context *ctx, struct gl_query_object *q) 150c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 151c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_context *brw = brw_context(ctx); 152c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct intel_context *intel = intel_context(ctx); 153c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query = (struct brw_query_object *)q; 154c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 155c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry switch (query->Base.Target) { 156c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_TIME_ELAPSED_EXT: 15734474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(query->bo); 15803f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke query->bo = drm_intel_bo_alloc(intel->bufmgr, "timer query", 4096, 4096); 15903f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke write_timestamp(intel, query->bo, 0); 160c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 161c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 162c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_SAMPLES_PASSED_ARB: 1633b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt /* Reset our driver's tracking of query state. */ 16434474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(query->bo); 1653b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt query->bo = NULL; 1663b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt query->first_index = -1; 1673b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt query->last_index = -1; 1683b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt 1693b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt brw->query.obj = query; 1703b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt intel->stats_wm++; 171c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 172c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 173c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_PRIMITIVES_GENERATED: 174c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* We don't actually query the hardware for this value; we keep track of 175c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * it a software counter. So just reset the counter. 176c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 177c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry brw->sol.primitives_generated = 0; 1788aa78c104a6fa9497cba558b54c41f6f2292bd74Jordan Justen brw->sol.counting_primitives_generated = true; 179c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry break; 180c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 181c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 182c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* We don't actually query the hardware for this value; we keep track of 183c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * it a software counter. So just reset the counter. 184c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 185c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry brw->sol.primitives_written = 0; 1868aa78c104a6fa9497cba558b54c41f6f2292bd74Jordan Justen brw->sol.counting_primitives_written = true; 187c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry break; 188c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 189c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry default: 190c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry assert(!"Unrecognized query target in brw_begin_query()"); 191c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 1923b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt } 193c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 194c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 195c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** 196c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt * Begin the ARB_occlusion_query query on a query object. 197c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt */ 198c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtstatic void 199f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergbrw_end_query(struct gl_context *ctx, struct gl_query_object *q) 200c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 201c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_context *brw = brw_context(ctx); 202c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct intel_context *intel = intel_context(ctx); 203c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query = (struct brw_query_object *)q; 204c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 205c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry switch (query->Base.Target) { 206c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_TIME_ELAPSED_EXT: 20703f14664b6b12bc7853866fe613d8af350e51e08Kenneth Graunke write_timestamp(intel, query->bo, 1); 2088d68a90e225d831a395ba788e425cb717eec1f9aChris Wilson intel_batchbuffer_flush(intel); 209c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 210c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 211c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry case GL_SAMPLES_PASSED_ARB: 2123b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt /* Flush the batchbuffer in case it has writes to our query BO. 2133b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt * Have later queries write to a new query BO so that further rendering 2143b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt * doesn't delay the collection of our results. 2153b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt */ 2163b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt if (query->bo) { 2173b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt brw_emit_query_end(brw); 2188d68a90e225d831a395ba788e425cb717eec1f9aChris Wilson intel_batchbuffer_flush(intel); 2193b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt 22034474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(brw->query.bo); 2213b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt brw->query.bo = NULL; 2223b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt } 2233b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt 2243b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt brw->query.obj = NULL; 2253b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt 2263b68b6c83e491d7f85baff6a31dcceee28622ae0Eric Anholt intel->stats_wm--; 227c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 228c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry 229c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_PRIMITIVES_GENERATED: 230c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* We don't actually query the hardware for this value; we keep track of 231c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * it in a software counter. So just read the counter and store it in 232c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * the query object. 233c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 234c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry query->Base.Result = brw->sol.primitives_generated; 2358aa78c104a6fa9497cba558b54c41f6f2292bd74Jordan Justen brw->sol.counting_primitives_generated = false; 236c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 237c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* And set brw->query.obj to NULL so that this query won't try to wait 238c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * for any rendering to complete. 239c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 240c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry query->bo = NULL; 241c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry break; 242c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 243c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: 244c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* We don't actually query the hardware for this value; we keep track of 245c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * it in a software counter. So just read the counter and store it in 246c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * the query object. 247c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 248c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry query->Base.Result = brw->sol.primitives_written; 2498aa78c104a6fa9497cba558b54c41f6f2292bd74Jordan Justen brw->sol.counting_primitives_written = false; 250c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 251c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry /* And set brw->query.obj to NULL so that this query won't try to wait 252c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry * for any rendering to complete. 253c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry */ 254c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry query->bo = NULL; 255c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry break; 256c59393b7069f59ca2a13bfb6500f2a5360c38031Paul Berry 257c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry default: 258c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry assert(!"Unrecognized query target in brw_end_query()"); 259c5e17a84983d7799fd842a62daaece3d97a670bePaul Berry break; 260c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt } 261c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 262c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 263f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergstatic void brw_wait_query(struct gl_context *ctx, struct gl_query_object *q) 264c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 265c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query = (struct brw_query_object *)q; 266c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 2677457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai brw_queryobj_get_results(ctx, query); 2682e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke query->Base.Ready = true; 269c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 270c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 271f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergstatic void brw_check_query(struct gl_context *ctx, struct gl_query_object *q) 272c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 273c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct brw_query_object *query = (struct brw_query_object *)q; 274c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 2753c1172f06636ff4aec24a6c68df937844da73a53Eric Anholt if (query->bo == NULL || !drm_intel_bo_busy(query->bo)) { 2767457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai brw_queryobj_get_results(ctx, query); 2772e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke query->Base.Ready = true; 278c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt } 279c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 280c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 281c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** Called to set up the query BO and account for its aperture space */ 282c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtvoid 283c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtbrw_prepare_query_begin(struct brw_context *brw) 284c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 285c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct intel_context *intel = &brw->intel; 286c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 287c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt /* Skip if we're not doing any queries. */ 288df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt if (!brw->query.obj) 289c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt return; 290c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 291c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt /* Get a new query BO if we're going to need it. */ 292c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt if (brw->query.bo == NULL || 293c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt brw->query.index * 2 + 1 >= 4096 / sizeof(uint64_t)) { 29434474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_unreference(brw->query.bo); 295c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt brw->query.bo = NULL; 296c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 29734474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt brw->query.bo = drm_intel_bo_alloc(intel->bufmgr, "query", 4096, 1); 298689aca782216d2666486dea02206cbc9c4162e0dZhenyu Wang 299689aca782216d2666486dea02206cbc9c4162e0dZhenyu Wang /* clear target buffer */ 3002e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke drm_intel_bo_map(brw->query.bo, true); 301689aca782216d2666486dea02206cbc9c4162e0dZhenyu Wang memset((char *)brw->query.bo->virtual, 0, 4096); 302689aca782216d2666486dea02206cbc9c4162e0dZhenyu Wang drm_intel_bo_unmap(brw->query.bo); 303689aca782216d2666486dea02206cbc9c4162e0dZhenyu Wang 304c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt brw->query.index = 0; 305c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt } 306c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 307c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 308c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** Called just before primitive drawing to get a beginning PS_DEPTH_COUNT. */ 309c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtvoid 310c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtbrw_emit_query_begin(struct brw_context *brw) 311c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 312c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct intel_context *intel = &brw->intel; 3137457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai struct gl_context *ctx = &intel->ctx; 314df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt struct brw_query_object *query = brw->query.obj; 315c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 316c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt /* Skip if we're not doing any queries, or we've emitted the start. */ 317df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt if (!query || brw->query.active) 318c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt return; 319c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 3203074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang if (intel->gen >= 6) { 3213074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang BEGIN_BATCH(8); 3223074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang 3233074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang /* workaround: CS stall required before depth stall. */ 32461d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2)); 3253074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(PIPE_CONTROL_CS_STALL); 3263074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); /* write address */ 3273074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); /* write data */ 3283074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang 32961d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2)); 3303074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(PIPE_CONTROL_DEPTH_STALL | 3313074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_WRITE_DEPTH_COUNT); 3323074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_RELOC(brw->query.bo, 3333074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 3343074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_GLOBAL_GTT_WRITE | 3353074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ((brw->query.index * 2) * sizeof(uint64_t))); 3363074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 3373074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ADVANCE_BATCH(); 3383074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang 3393074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang } else { 3403074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang BEGIN_BATCH(4); 34161d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2) | 3423074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_DEPTH_STALL | 3433074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_WRITE_DEPTH_COUNT); 3443074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang /* This object could be mapped cacheable, but we don't have an exposed 3453074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang * mechanism to support that. Since it's going uncached, tell GEM that 3463074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang * we're writing to it. The usual clflush should be all that's required 3473074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang * to pick up the results. 3483074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang */ 3493074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_RELOC(brw->query.bo, 3503074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 3513074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_GLOBAL_GTT_WRITE | 3523074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ((brw->query.index * 2) * sizeof(uint64_t))); 3533074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 3543074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 3553074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ADVANCE_BATCH(); 3563074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang } 357c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 358df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt if (query->bo != brw->query.bo) { 359df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt if (query->bo != NULL) 3607457da5edd4a33c2581f10608ce5bcf0e254c5f9Zou Nan hai brw_queryobj_get_results(ctx, query); 36134474fa4119378ef9fbb9fb557cc19c0a1ca1f7eEric Anholt drm_intel_bo_reference(brw->query.bo); 362df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt query->bo = brw->query.bo; 363df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt query->first_index = brw->query.index; 364c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt } 365df3590f570cb88eb9695b443208d7576b5867fd1Eric Anholt query->last_index = brw->query.index; 3662e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke brw->query.active = true; 367c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 368c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 369c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt/** Called at batchbuffer flush to get an ending PS_DEPTH_COUNT */ 370c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtvoid 371c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtbrw_emit_query_end(struct brw_context *brw) 372c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 373c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt struct intel_context *intel = &brw->intel; 374c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 375c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt if (!brw->query.active) 376c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt return; 377c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 3783074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang if (intel->gen >= 6) { 3793074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang BEGIN_BATCH(8); 3803074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang /* workaround: CS stall required before depth stall. */ 38161d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2)); 3823074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(PIPE_CONTROL_CS_STALL); 3833074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); /* write address */ 3843074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); /* write data */ 3853074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang 38661d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2)); 3873074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(PIPE_CONTROL_DEPTH_STALL | 3883074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_WRITE_DEPTH_COUNT); 3893074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_RELOC(brw->query.bo, 3903074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 3913074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_GLOBAL_GTT_WRITE | 3923074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ((brw->query.index * 2 + 1) * sizeof(uint64_t))); 3933074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 3943074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ADVANCE_BATCH(); 3953074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang 3963074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang } else { 3973074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang BEGIN_BATCH(4); 39861d0b9f52c6be4a4a64c30ea3a2a93ef8260c67bKenneth Graunke OUT_BATCH(_3DSTATE_PIPE_CONTROL | (4 - 2) | 3993074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_DEPTH_STALL | 4003074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_WRITE_DEPTH_COUNT); 4013074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_RELOC(brw->query.bo, 4023074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 4033074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang PIPE_CONTROL_GLOBAL_GTT_WRITE | 4043074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ((brw->query.index * 2 + 1) * sizeof(uint64_t))); 4053074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 4063074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang OUT_BATCH(0); 4073074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang ADVANCE_BATCH(); 4083074b61f64601be4620f1fb3c48c7c6024d3fd57Zhenyu Wang } 409c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 4102e5a1a254ed81b1d3efa6064f48183eefac784d0Kenneth Graunke brw->query.active = false; 411c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt brw->query.index++; 412c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 413c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt 414c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholtvoid brw_init_queryobj_functions(struct dd_function_table *functions) 415c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt{ 416c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->NewQueryObject = brw_new_query_object; 417c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->DeleteQuery = brw_delete_query; 418c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->BeginQuery = brw_begin_query; 419c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->EndQuery = brw_end_query; 420c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->CheckQuery = brw_check_query; 421c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt functions->WaitQuery = brw_wait_query; 422c157cfc6376f7469ab272b18868183e5ff9ac754Eric Anholt} 423