nv50_screen.c revision 3c6309e2f792af0c353e2a04317a83f624dfa263
1c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany/* 2c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * Copyright 2008 Ben Skeggs 3c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * 4c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * Permission is hereby granted, free of charge, to any person obtaining a 5c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * copy of this software and associated documentation files (the "Software"), 6c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * to deal in the Software without restriction, including without limitation 7c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * and/or sell copies of the Software, and to permit persons to whom the 9c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * Software is furnished to do so, subject to the following conditions: 10c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * 11c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * The above copyright notice and this permission notice shall be included in 12c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * all copies or substantial portions of the Software. 13c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * 149ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 159ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 169ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 179ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany * SOFTWARE. 21c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany */ 22c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 23c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "util/u_format_s3tc.h" 24c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "pipe/p_screen.h" 25c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 26c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "nv50_context.h" 27c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "nv50_screen.h" 28c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "nv50_resource.h" 29c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "nv50_program.h" 30c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 31c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#include "nouveau/nouveau_stateobj.h" 32c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 33c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic boolean 34c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynv50_screen_is_format_supported(struct pipe_screen *pscreen, 35c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany enum pipe_format format, 36c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany enum pipe_texture_target target, 37c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany unsigned sample_count, 38c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany unsigned usage, unsigned geom_flags) 391ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov{ 401ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (sample_count > 1) 411ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return FALSE; 421ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 431ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if (!util_format_s3tc_enabled) { 441ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov switch (format) { 451ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_FORMAT_DXT1_RGB: 461ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_FORMAT_DXT1_RGBA: 471ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_FORMAT_DXT3_RGBA: 481ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_FORMAT_DXT5_RGBA: 491ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return FALSE; 501ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov default: 511ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov break; 521ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 531ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov } 541ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 551ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov switch (format) { 561ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_FORMAT_Z16_UNORM: 571ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov if ((nouveau_screen(pscreen)->device->chipset & 0xf0) != 0xa0) 581ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return FALSE; 59678e5436c6c1ecbd0cf50ce80bc7a2afb904c0efEvgeniy Stepanov break; 60c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany default: 61c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany break; 62c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 634fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany 644fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany /* transfers & shared are always supported */ 65c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany usage &= ~(PIPE_BIND_TRANSFER_READ | 66c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany PIPE_BIND_TRANSFER_WRITE | 67c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany PIPE_BIND_SHARED); 681ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 691ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return (nv50_format_table[format].usage & usage) == usage; 70c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 711ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov 721ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovstatic int 731ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonovnv50_screen_get_param(struct pipe_screen *pscreen, enum pipe_cap param) 741ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov{ 751ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov switch (param) { 761ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS: 771ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 32; 781ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_MAX_VERTEX_TEXTURE_UNITS: 791ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 32; 801ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_MAX_COMBINED_SAMPLERS: 811ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 64; 821ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_NPOT_TEXTURES: 83c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 84c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TWO_SIDED_STENCIL: 851ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 1; 86c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_GLSL: 87c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_SM3: 88c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 89c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_ANISOTROPIC_FILTER: 901ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 1; 911ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_POINT_SPRITE: 92c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 931ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_MAX_RENDER_TARGETS: 941ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 8; 95c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_OCCLUSION_QUERY: 96c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 97c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TIMER_QUERY: 98c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 99c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_STREAM_OUTPUT: 1001ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 0; 1011ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_TEXTURE_SHADOW_MAP: 1021ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 1; 1031ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_MAX_TEXTURE_2D_LEVELS: 1041ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 13; 105c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_TEXTURE_3D_LEVELS: 106c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 10; 1074fa111ccf225648a3de447a7a1ed6420b3c4b3afKostya Serebryany case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS: 1081ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov return 13; 109c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TEXTURE_MIRROR_CLAMP: 1101ca535700966cf5019dcc6684a62a734a7b96974Alexey Samsonov case PIPE_CAP_TEXTURE_MIRROR_REPEAT: 111c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 112c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TEXTURE_SWIZZLE: 113c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 114c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_BLEND_EQUATION_SEPARATE: 115c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 116c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_INDEP_BLEND_ENABLE: 117c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 118c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_INDEP_BLEND_FUNC: 119c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 120c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE: 121c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 122c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT: 123c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER: 124c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 125c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT: 126c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER: 127c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 128c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_DEPTH_CLAMP: 129c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 130c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany default: 131c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 132c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 133c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 134c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 135c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 136c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic int 137c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynv50_screen_get_shader_param(struct pipe_screen *pscreen, unsigned shader, 138c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany enum pipe_shader_cap param) 139c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany{ 140c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany switch(shader) { 141c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_FRAGMENT: 142c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_VERTEX: 143c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany break; 144c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_GEOMETRY: 145c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany default: 146c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 147c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 148c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 149c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany switch(param) { 150c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_INSTRUCTIONS: 151c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS: 152c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_TEX_INSTRUCTIONS: 153c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_TEX_INDIRECTIONS: /* arbitrary limit */ 154c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 16384; 155c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_CONTROL_FLOW_DEPTH: /* need stack bo */ 156c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 4; 157c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_INPUTS: /* 128 / 4 with GP */ 158c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (shader == PIPE_SHADER_GEOMETRY) 159c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 128 / 4; 160c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany else 161c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 64 / 4; 162c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_CONSTS: 163c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 65536 / 16; 164c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_CONST_BUFFERS: /* 16 - 1, but not implemented */ 165c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 166c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_ADDRS: /* no spilling atm */ 167c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 168c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_PREDS: /* not yet handled */ 169c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 170c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_MAX_TEMPS: /* no spilling atm */ 171c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return NV50_CAP_MAX_PROGRAM_TEMPS; 1729ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany case PIPE_SHADER_CAP_TGSI_CONT_SUPPORTED: 173c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 174c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_INDIRECT_INPUT_ADDR: 175c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_INDIRECT_OUTPUT_ADDR: 176c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR: 177c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_SHADER_CAP_INDIRECT_CONST_ADDR: 178c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 1; 179c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany default: 180c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0; 181c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 182c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 183c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 184c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic float 185c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynv50_screen_get_paramf(struct pipe_screen *pscreen, enum pipe_cap param) 186c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany{ 187c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany switch (param) { 188c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_LINE_WIDTH: 189c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_LINE_WIDTH_AA: 190c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 10.0; 191c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_POINT_WIDTH: 192c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_POINT_WIDTH_AA: 193c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 64.0; 194c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_TEXTURE_ANISOTROPY: 195c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 16.0; 196c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case PIPE_CAP_MAX_TEXTURE_LOD_BIAS: 197c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 4.0; 1989ada1f376498647c8035f52b36d98bdf0f6363e6Kostya Serebryany default: 199c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany NOUVEAU_ERR("Unknown PIPE_CAP %d\n", param); 200c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany return 0.0; 201c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 202c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 203c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 204c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanystatic void 205c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynv50_screen_destroy(struct pipe_screen *pscreen) 206c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany{ 207c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany struct nv50_screen *screen = nv50_screen(pscreen); 208c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany unsigned i; 209c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 210c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany for (i = 0; i < 3; i++) { 211c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (screen->constbuf_parm[i]) 212c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_bo_ref(NULL, &screen->constbuf_parm[i]); 213c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany } 214c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 215c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (screen->constbuf_misc[0]) 216c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_bo_ref(NULL, &screen->constbuf_misc[0]); 217c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (screen->tic) 218c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_bo_ref(NULL, &screen->tic); 219c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany if (screen->tsc) 220c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_bo_ref(NULL, &screen->tsc); 221c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 222c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_notifier_free(&screen->sync); 223c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_grobj_free(&screen->tesla); 224c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_grobj_free(&screen->eng2d); 225c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_grobj_free(&screen->m2mf); 226c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_resource_destroy(&screen->immd_heap); 227c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany nouveau_screen_fini(&screen->base); 228c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany FREE(screen); 229c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany} 230c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 231c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany#define BGN_RELOC(ch, bo, gr, m, n, fl) \ 232c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany OUT_RELOC(ch, bo, (n << 18) | (gr->subc << 13) | m, fl, 0, 0) 233c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 234c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanyvoid 235c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryanynv50_screen_reloc_constbuf(struct nv50_screen *screen, unsigned cbi) 236c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany{ 237c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany struct nouveau_bo *bo; 238c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany struct nouveau_channel *chan = screen->base.channel; 239c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany struct nouveau_grobj *tesla = screen->tesla; 240c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany unsigned size; 241c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany const unsigned rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY; 242c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany 243c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany switch (cbi) { 244c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany case NV50_CB_PMISC: 245c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany bo = screen->constbuf_misc[0]; 246c7be4077b90cae43f8e6d2d4de66ae64111dd715Kostya Serebryany size = 0x200; 247 break; 248 case NV50_CB_PVP: 249 case NV50_CB_PFP: 250 case NV50_CB_PGP: 251 bo = screen->constbuf_parm[cbi - NV50_CB_PVP]; 252 size = 0; 253 break; 254 default: 255 return; 256 } 257 258 BGN_RELOC (chan, bo, tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3, rl); 259 OUT_RELOCh(chan, bo, 0, rl); 260 OUT_RELOCl(chan, bo, 0, rl); 261 OUT_RELOC (chan, bo, (cbi << 16) | size, rl, 0, 0); 262} 263 264void 265nv50_screen_relocs(struct nv50_screen *screen) 266{ 267 struct nouveau_channel *chan = screen->base.channel; 268 struct nouveau_grobj *tesla = screen->tesla; 269 unsigned i; 270 const unsigned rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY; 271 272 MARK_RING (chan, 28, 26); 273 274 /* cause grobj autobind */ 275 BEGIN_RING(chan, tesla, 0x0100, 1); 276 OUT_RING (chan, 0); 277 278 BGN_RELOC (chan, screen->tic, tesla, NV50TCL_TIC_ADDRESS_HIGH, 2, rl); 279 OUT_RELOCh(chan, screen->tic, 0, rl); 280 OUT_RELOCl(chan, screen->tic, 0, rl); 281 282 BGN_RELOC (chan, screen->tsc, tesla, NV50TCL_TSC_ADDRESS_HIGH, 2, rl); 283 OUT_RELOCh(chan, screen->tsc, 0, rl); 284 OUT_RELOCl(chan, screen->tsc, 0, rl); 285 286 nv50_screen_reloc_constbuf(screen, NV50_CB_PMISC); 287 288 BGN_RELOC (chan, screen->constbuf_misc[0], 289 tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3, rl); 290 OUT_RELOCh(chan, screen->constbuf_misc[0], 0x200, rl); 291 OUT_RELOCl(chan, screen->constbuf_misc[0], 0x200, rl); 292 OUT_RELOC (chan, screen->constbuf_misc[0], 293 (NV50_CB_AUX << 16) | 0x0200, rl, 0, 0); 294 295 for (i = 0; i < 3; ++i) 296 nv50_screen_reloc_constbuf(screen, NV50_CB_PVP + i); 297 298 BGN_RELOC (chan, screen->stack_bo, 299 tesla, NV50TCL_STACK_ADDRESS_HIGH, 2, rl); 300 OUT_RELOCh(chan, screen->stack_bo, 0, rl); 301 OUT_RELOCl(chan, screen->stack_bo, 0, rl); 302 303 if (!screen->cur_ctx->req_lmem) 304 return; 305 306 BGN_RELOC (chan, screen->local_bo, 307 tesla, NV50TCL_LOCAL_ADDRESS_HIGH, 2, rl); 308 OUT_RELOCh(chan, screen->local_bo, 0, rl); 309 OUT_RELOCl(chan, screen->local_bo, 0, rl); 310} 311 312#ifndef NOUVEAU_GETPARAM_GRAPH_UNITS 313# define NOUVEAU_GETPARAM_GRAPH_UNITS 13 314#endif 315 316extern int nouveau_device_get_param(struct nouveau_device *dev, 317 uint64_t param, uint64_t *value); 318 319struct pipe_screen * 320nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev) 321{ 322 struct nv50_screen *screen = CALLOC_STRUCT(nv50_screen); 323 struct nouveau_channel *chan; 324 struct pipe_screen *pscreen; 325 uint64_t value; 326 unsigned chipset = dev->chipset; 327 unsigned tesla_class = 0; 328 unsigned stack_size, local_size, max_warps; 329 int ret, i; 330 const unsigned rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_RD; 331 332 if (!screen) 333 return NULL; 334 pscreen = &screen->base.base; 335 336 ret = nouveau_screen_init(&screen->base, dev); 337 if (ret) { 338 nv50_screen_destroy(pscreen); 339 return NULL; 340 } 341 chan = screen->base.channel; 342 343 pscreen->winsys = ws; 344 pscreen->destroy = nv50_screen_destroy; 345 pscreen->get_param = nv50_screen_get_param; 346 pscreen->get_shader_param = nv50_screen_get_shader_param; 347 pscreen->get_paramf = nv50_screen_get_paramf; 348 pscreen->is_format_supported = nv50_screen_is_format_supported; 349 pscreen->context_create = nv50_create; 350 351 nv50_screen_init_resource_functions(pscreen); 352 353 /* DMA engine object */ 354 ret = nouveau_grobj_alloc(chan, 0xbeef5039, 355 NV50_MEMORY_TO_MEMORY_FORMAT, &screen->m2mf); 356 if (ret) { 357 NOUVEAU_ERR("Error creating M2MF object: %d\n", ret); 358 nv50_screen_destroy(pscreen); 359 return NULL; 360 } 361 362 /* 2D object */ 363 ret = nouveau_grobj_alloc(chan, 0xbeef502d, NV50_2D, &screen->eng2d); 364 if (ret) { 365 NOUVEAU_ERR("Error creating 2D object: %d\n", ret); 366 nv50_screen_destroy(pscreen); 367 return NULL; 368 } 369 370 /* 3D object */ 371 switch (chipset & 0xf0) { 372 case 0x50: 373 tesla_class = NV50TCL; 374 break; 375 case 0x80: 376 case 0x90: 377 tesla_class = NV84TCL; 378 break; 379 case 0xa0: 380 switch (chipset) { 381 case 0xa0: 382 case 0xaa: 383 case 0xac: 384 tesla_class = NVA0TCL; 385 break; 386 default: 387 tesla_class = NVA8TCL; 388 break; 389 } 390 break; 391 default: 392 NOUVEAU_ERR("Not a known NV50 chipset: NV%02x\n", chipset); 393 nv50_screen_destroy(pscreen); 394 return NULL; 395 } 396 397 ret = nouveau_grobj_alloc(chan, 0xbeef5097, tesla_class, 398 &screen->tesla); 399 if (ret) { 400 NOUVEAU_ERR("Error creating 3D object: %d\n", ret); 401 nv50_screen_destroy(pscreen); 402 return NULL; 403 } 404 405 /* this is necessary for the new RING_3D / statebuffer code */ 406 BIND_RING(chan, screen->tesla, 7); 407 408 /* Sync notifier */ 409 ret = nouveau_notifier_alloc(chan, 0xbeef0301, 1, &screen->sync); 410 if (ret) { 411 NOUVEAU_ERR("Error creating notifier object: %d\n", ret); 412 nv50_screen_destroy(pscreen); 413 return NULL; 414 } 415 416 /* Static M2MF init */ 417 BEGIN_RING(chan, screen->m2mf, 418 NV04_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); 419 OUT_RING (chan, screen->sync->handle); 420 OUT_RING (chan, chan->vram->handle); 421 OUT_RING (chan, chan->vram->handle); 422 423 /* Static 2D init */ 424 BEGIN_RING(chan, screen->eng2d, NV50_2D_DMA_NOTIFY, 4); 425 OUT_RING (chan, screen->sync->handle); 426 OUT_RING (chan, chan->vram->handle); 427 OUT_RING (chan, chan->vram->handle); 428 OUT_RING (chan, chan->vram->handle); 429 BEGIN_RING(chan, screen->eng2d, NV50_2D_OPERATION, 1); 430 OUT_RING (chan, NV50_2D_OPERATION_SRCCOPY); 431 BEGIN_RING(chan, screen->eng2d, NV50_2D_CLIP_ENABLE, 1); 432 OUT_RING (chan, 0); 433 BEGIN_RING(chan, screen->eng2d, 0x0888, 1); 434 OUT_RING (chan, 1); 435 436 /* Static tesla init */ 437 BEGIN_RING(chan, screen->tesla, NV50TCL_COND_MODE, 1); 438 OUT_RING (chan, NV50TCL_COND_MODE_ALWAYS); 439 BEGIN_RING(chan, screen->tesla, NV50TCL_DMA_NOTIFY, 1); 440 OUT_RING (chan, screen->sync->handle); 441 BEGIN_RING(chan, screen->tesla, NV50TCL_DMA_ZETA, 11); 442 for (i = 0; i < 11; i++) 443 OUT_RING (chan, chan->vram->handle); 444 BEGIN_RING(chan, screen->tesla, 445 NV50TCL_DMA_COLOR(0), NV50TCL_DMA_COLOR__SIZE); 446 for (i = 0; i < NV50TCL_DMA_COLOR__SIZE; i++) 447 OUT_RING (chan, chan->vram->handle); 448 449 BEGIN_RING(chan, screen->tesla, NV50TCL_RT_CONTROL, 1); 450 OUT_RING (chan, 1); 451 452 /* activate all 32 lanes (threads) in a warp */ 453 BEGIN_RING(chan, screen->tesla, NV50TCL_REG_MODE, 1); 454 OUT_RING (chan, NV50TCL_REG_MODE_STRIPED); 455 BEGIN_RING(chan, screen->tesla, 0x1400, 1); 456 OUT_RING (chan, 0xf); 457 458 /* max TIC (bits 4:8) & TSC (ignored) bindings, per program type */ 459 for (i = 0; i < 3; ++i) { 460 BEGIN_RING(chan, screen->tesla, NV50TCL_TEX_LIMITS(i), 1); 461 OUT_RING (chan, 0x54); 462 } 463 464 /* origin is top left (set to 1 for bottom left) */ 465 BEGIN_RING(chan, screen->tesla, NV50TCL_Y_ORIGIN_BOTTOM, 1); 466 OUT_RING (chan, 0); 467 BEGIN_RING(chan, screen->tesla, NV50TCL_VP_REG_ALLOC_RESULT, 1); 468 OUT_RING (chan, 8); 469 470 BEGIN_RING(chan, screen->tesla, NV50TCL_CLEAR_FLAGS, 1); 471 OUT_RING (chan, NV50TCL_CLEAR_FLAGS_D3D); 472 473 /* constant buffers for immediates and VP/FP parameters */ 474 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (32 * 4) * 4, 475 &screen->constbuf_misc[0]); 476 if (ret) { 477 nv50_screen_destroy(pscreen); 478 return NULL; 479 } 480 BEGIN_RING(chan, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 481 OUT_RELOCh(chan, screen->constbuf_misc[0], 0, rl); 482 OUT_RELOCl(chan, screen->constbuf_misc[0], 0, rl); 483 OUT_RING (chan, (NV50_CB_PMISC << 16) | 0x0200); 484 BEGIN_RING(chan, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 485 OUT_RELOCh(chan, screen->constbuf_misc[0], 0x200, rl); 486 OUT_RELOCl(chan, screen->constbuf_misc[0], 0x200, rl); 487 OUT_RING (chan, (NV50_CB_AUX << 16) | 0x0200); 488 489 for (i = 0; i < 3; i++) { 490 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, (4096 * 4) * 4, 491 &screen->constbuf_parm[i]); 492 if (ret) { 493 nv50_screen_destroy(pscreen); 494 return NULL; 495 } 496 BEGIN_RING(chan, screen->tesla, NV50TCL_CB_DEF_ADDRESS_HIGH, 3); 497 OUT_RELOCh(chan, screen->constbuf_parm[i], 0, rl); 498 OUT_RELOCl(chan, screen->constbuf_parm[i], 0, rl); 499 /* CB_DEF_SET_SIZE value of 0x0000 means 65536 */ 500 OUT_RING (chan, ((NV50_CB_PVP + i) << 16) | 0x0000); 501 } 502 503 if (nouveau_resource_init(&screen->immd_heap, 0, 128)) { 504 NOUVEAU_ERR("Error initialising shader immediates heap.\n"); 505 nv50_screen_destroy(pscreen); 506 return NULL; 507 } 508 509 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 3 * 32 * (8 * 4), 510 &screen->tic); 511 if (ret) { 512 nv50_screen_destroy(pscreen); 513 return NULL; 514 } 515 BEGIN_RING(chan, screen->tesla, NV50TCL_TIC_ADDRESS_HIGH, 3); 516 OUT_RELOCh(chan, screen->tic, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 517 OUT_RELOCl(chan, screen->tic, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 518 OUT_RING (chan, 3 * 32 - 1); 519 520 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 0, 3 * 32 * (8 * 4), 521 &screen->tsc); 522 if (ret) { 523 nv50_screen_destroy(pscreen); 524 return NULL; 525 } 526 BEGIN_RING(chan, screen->tesla, NV50TCL_TSC_ADDRESS_HIGH, 3); 527 OUT_RELOCh(chan, screen->tsc, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 528 OUT_RELOCl(chan, screen->tsc, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD); 529 OUT_RING (chan, 0); /* ignored if TSC_LINKED (0x1234) == 1 */ 530 531 /* map constant buffers: 532 * B = buffer ID (maybe more than 1 byte) 533 * N = CB index used in shader instruction 534 * P = program type (0 = VP, 2 = GP, 3 = FP) 535 * SET_PROGRAM_CB = 0x000BBNP1 536 */ 537 BEGIN_RING_NI(chan, screen->tesla, NV50TCL_SET_PROGRAM_CB, 8); 538 /* bind immediate buffer */ 539 OUT_RING (chan, 0x001 | (NV50_CB_PMISC << 12)); 540 OUT_RING (chan, 0x021 | (NV50_CB_PMISC << 12)); 541 OUT_RING (chan, 0x031 | (NV50_CB_PMISC << 12)); 542 /* bind auxiliary constbuf to immediate data bo */ 543 OUT_RING (chan, 0x201 | (NV50_CB_AUX << 12)); 544 OUT_RING (chan, 0x221 | (NV50_CB_AUX << 12)); 545 /* bind parameter buffers */ 546 OUT_RING (chan, 0x101 | (NV50_CB_PVP << 12)); 547 OUT_RING (chan, 0x121 | (NV50_CB_PGP << 12)); 548 OUT_RING (chan, 0x131 | (NV50_CB_PFP << 12)); 549 550 /* shader stack */ 551 nouveau_device_get_param(dev, NOUVEAU_GETPARAM_GRAPH_UNITS, &value); 552 553 max_warps = util_bitcount(value & 0xffff); 554 max_warps *= util_bitcount((value >> 24) & 0xf) * 32; 555 556 stack_size = max_warps * 64 * 8; 557 558 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 1 << 16, 559 stack_size, &screen->stack_bo); 560 if (ret) { 561 nv50_screen_destroy(pscreen); 562 return NULL; 563 } 564 BEGIN_RING(chan, screen->tesla, NV50TCL_STACK_ADDRESS_HIGH, 3); 565 OUT_RELOCh(chan, screen->stack_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 566 OUT_RELOCl(chan, screen->stack_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 567 OUT_RING (chan, 4); 568 569 local_size = (NV50_CAP_MAX_PROGRAM_TEMPS * 16) * max_warps * 32; 570 571 ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 1 << 16, 572 local_size, &screen->local_bo); 573 if (ret) { 574 nv50_screen_destroy(pscreen); 575 return NULL; 576 } 577 578 local_size = NV50_CAP_MAX_PROGRAM_TEMPS * 16; 579 580 BEGIN_RING(chan, screen->tesla, NV50TCL_LOCAL_ADDRESS_HIGH, 3); 581 OUT_RELOCh(chan, screen->local_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 582 OUT_RELOCl(chan, screen->local_bo, 0, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR); 583 OUT_RING (chan, util_unsigned_logbase2(local_size / 8)); 584 585 /* Vertex array limits - max them out */ 586 for (i = 0; i < 16; i++) { 587 BEGIN_RING(chan, screen->tesla, 588 NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2); 589 OUT_RING (chan, 0x000000ff); 590 OUT_RING (chan, 0xffffffff); 591 } 592 593 BEGIN_RING(chan, screen->tesla, NV50TCL_DEPTH_RANGE_NEAR(0), 2); 594 OUT_RINGf (chan, 0.0f); 595 OUT_RINGf (chan, 1.0f); 596 597 BEGIN_RING(chan, screen->tesla, NV50TCL_VIEWPORT_TRANSFORM_EN, 1); 598 OUT_RING (chan, 1); 599 600 /* no dynamic combination of TIC & TSC entries => only BIND_TIC used */ 601 BEGIN_RING(chan, screen->tesla, NV50TCL_LINKED_TSC, 1); 602 OUT_RING (chan, 1); 603 604 BEGIN_RING(chan, screen->tesla, NV50TCL_EDGEFLAG_ENABLE, 1); 605 OUT_RING (chan, 1); /* default edgeflag to TRUE */ 606 607 FIRE_RING (chan); 608 609 screen->force_push = debug_get_bool_option("NV50_ALWAYS_PUSH", FALSE); 610 if(!screen->force_push) 611 screen->base.vertex_buffer_flags = screen->base.index_buffer_flags = NOUVEAU_BO_GART; 612 return pscreen; 613} 614 615