blob: fc1b3c980efe2a9ea3225caf1182c7b75d9b597b [file] [log] [blame]
/**********************************************************
* Copyright 2008-2009 VMware, Inc. All rights reserved.
*
* 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 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 "util/u_memory.h"
#include "pipe/p_inlines.h"
#include "util/u_string.h"
#include "util/u_math.h"
#include "svga_winsys.h"
#include "svga_context.h"
#include "svga_screen.h"
#include "svga_screen_texture.h"
#include "svga_screen_buffer.h"
#include "svga_cmd.h"
#include "svga_debug.h"
#include "svga_hw_reg.h"
#include "svga3d_shaderdefs.h"
#ifdef DEBUG
int SVGA_DEBUG = 0;
static const struct debug_named_value svga_debug_flags[] = {
{ "dma", DEBUG_DMA },
{ "tgsi", DEBUG_TGSI },
{ "pipe", DEBUG_PIPE },
{ "state", DEBUG_STATE },
{ "screen", DEBUG_SCREEN },
{ "tex", DEBUG_TEX },
{ "swtnl", DEBUG_SWTNL },
{ "const", DEBUG_CONSTS },
{ "viewport", DEBUG_VIEWPORT },
{ "views", DEBUG_VIEWS },
{ "perf", DEBUG_PERF },
{ "flush", DEBUG_FLUSH },
{ "sync", DEBUG_SYNC },
{ "cache", DEBUG_CACHE },
{NULL, 0}
};
#endif
static const char *
svga_get_vendor( struct pipe_screen *pscreen )
{
return "VMware, Inc.";
}
static const char *
svga_get_name( struct pipe_screen *pscreen )
{
#ifdef DEBUG
/* Only return internal details in the DEBUG version:
*/
return "SVGA3D; build: DEBUG; mutex: " PIPE_ATOMIC;
#else
return "SVGA3D; build: RELEASE; ";
#endif
}
static float
svga_get_paramf(struct pipe_screen *screen, int param)
{
struct svga_screen *svgascreen = svga_screen(screen);
struct svga_winsys_screen *sws = svgascreen->sws;
SVGA3dDevCapResult result;
switch (param) {
case PIPE_CAP_MAX_LINE_WIDTH:
/* fall-through */
case PIPE_CAP_MAX_LINE_WIDTH_AA:
return 7.0;
case PIPE_CAP_MAX_POINT_WIDTH:
/* fall-through */
case PIPE_CAP_MAX_POINT_WIDTH_AA:
/* Keep this to a reasonable size to avoid failures in
* conform/pntaa.c:
*/
return 80.0;
case PIPE_CAP_MAX_TEXTURE_ANISOTROPY:
return 4.0;
case PIPE_CAP_MAX_TEXTURE_LOD_BIAS:
return 16.0;
case PIPE_CAP_MAX_TEXTURE_IMAGE_UNITS:
return 16;
case PIPE_CAP_NPOT_TEXTURES:
return 1;
case PIPE_CAP_TWO_SIDED_STENCIL:
return 1;
case PIPE_CAP_GLSL:
return svgascreen->use_ps30 && svgascreen->use_vs30;
case PIPE_CAP_ANISOTROPIC_FILTER:
return 1;
case PIPE_CAP_POINT_SPRITE:
return 1;
case PIPE_CAP_MAX_RENDER_TARGETS:
if(!sws->get_cap(sws, SVGA3D_DEVCAP_MAX_RENDER_TARGETS, &result))
return 1;
if(!result.u)
return 1;
return MIN2(result.u, PIPE_MAX_COLOR_BUFS);
case PIPE_CAP_OCCLUSION_QUERY:
return 1;
case PIPE_CAP_TEXTURE_SHADOW_MAP:
return 1;
case PIPE_CAP_MAX_TEXTURE_2D_LEVELS:
return SVGA_MAX_TEXTURE_LEVELS;
case PIPE_CAP_MAX_TEXTURE_3D_LEVELS:
return 8; /* max 128x128x128 */
case PIPE_CAP_MAX_TEXTURE_CUBE_LEVELS:
return SVGA_MAX_TEXTURE_LEVELS;
case PIPE_CAP_TEXTURE_MIRROR_REPEAT: /* req. for GL 1.4 */
return 1;
case PIPE_CAP_BLEND_EQUATION_SEPARATE: /* req. for GL 1.5 */
return 1;
default:
return 0;
}
}
/* This is a fairly pointless interface
*/
static int
svga_get_param(struct pipe_screen *screen, int param)
{
return (int) svga_get_paramf( screen, param );
}
static INLINE SVGA3dDevCapIndex
svga_translate_format_cap(enum pipe_format format)
{
switch(format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_A8R8G8B8;
case PIPE_FORMAT_X8R8G8B8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_X8R8G8B8;
case PIPE_FORMAT_R5G6B5_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_R5G6B5;
case PIPE_FORMAT_A1R5G5B5_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_A1R5G5B5;
case PIPE_FORMAT_A4R4G4B4_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_A4R4G4B4;
case PIPE_FORMAT_Z16_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_Z_D16;
case PIPE_FORMAT_Z24S8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_Z_D24S8;
case PIPE_FORMAT_Z24X8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_Z_D24X8;
case PIPE_FORMAT_A8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_ALPHA8;
case PIPE_FORMAT_L8_UNORM:
return SVGA3D_DEVCAP_SURFACEFMT_LUMINANCE8;
case PIPE_FORMAT_DXT1_RGB:
case PIPE_FORMAT_DXT1_RGBA:
return SVGA3D_DEVCAP_SURFACEFMT_DXT1;
case PIPE_FORMAT_DXT3_RGBA:
return SVGA3D_DEVCAP_SURFACEFMT_DXT3;
case PIPE_FORMAT_DXT5_RGBA:
return SVGA3D_DEVCAP_SURFACEFMT_DXT5;
default:
return SVGA3D_DEVCAP_MAX;
}
}
static boolean
svga_is_format_supported( struct pipe_screen *screen,
enum pipe_format format,
enum pipe_texture_target target,
unsigned tex_usage,
unsigned geom_flags )
{
struct svga_winsys_screen *sws = svga_screen(screen)->sws;
SVGA3dDevCapIndex index;
SVGA3dDevCapResult result;
assert(tex_usage);
/* Override host capabilities */
if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET) {
switch(format) {
/* Often unsupported/problematic. This means we end up with the same
* visuals for all virtual hardware implementations.
*/
case PIPE_FORMAT_A4R4G4B4_UNORM:
case PIPE_FORMAT_A1R5G5B5_UNORM:
return FALSE;
/* Simulate ability to render into compressed textures */
case PIPE_FORMAT_DXT1_RGB:
case PIPE_FORMAT_DXT1_RGBA:
case PIPE_FORMAT_DXT3_RGBA:
case PIPE_FORMAT_DXT5_RGBA:
return TRUE;
default:
break;
}
}
/* Try to query the host */
index = svga_translate_format_cap(format);
if( index < SVGA3D_DEVCAP_MAX &&
sws->get_cap(sws, index, &result) )
{
SVGA3dSurfaceFormatCaps mask;
mask.value = 0;
if (tex_usage & PIPE_TEXTURE_USAGE_RENDER_TARGET)
mask.offscreenRenderTarget = 1;
if (tex_usage & PIPE_TEXTURE_USAGE_DEPTH_STENCIL)
mask.zStencil = 1;
if (tex_usage & PIPE_TEXTURE_USAGE_SAMPLER)
mask.texture = 1;
if ((result.u & mask.value) == mask.value)
return TRUE;
else
return FALSE;
}
/* Use our translate functions directly rather than relying on a
* duplicated list of supported formats which is prone to getting
* out of sync:
*/
if(tex_usage & (PIPE_TEXTURE_USAGE_RENDER_TARGET | PIPE_TEXTURE_USAGE_DEPTH_STENCIL))
return svga_translate_format_render(format) != SVGA3D_FORMAT_INVALID;
else
return svga_translate_format(format) != SVGA3D_FORMAT_INVALID;
}
static void
svga_fence_reference(struct pipe_screen *screen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
struct svga_winsys_screen *sws = svga_screen(screen)->sws;
sws->fence_reference(sws, ptr, fence);
}
static int
svga_fence_signalled(struct pipe_screen *screen,
struct pipe_fence_handle *fence,
unsigned flag)
{
struct svga_winsys_screen *sws = svga_screen(screen)->sws;
return sws->fence_signalled(sws, fence, flag);
}
static int
svga_fence_finish(struct pipe_screen *screen,
struct pipe_fence_handle *fence,
unsigned flag)
{
struct svga_winsys_screen *sws = svga_screen(screen)->sws;
SVGA_DBG(DEBUG_DMA|DEBUG_PERF, "%s fence_ptr %p\n",
__FUNCTION__, fence);
return sws->fence_finish(sws, fence, flag);
}
static void
svga_destroy_screen( struct pipe_screen *screen )
{
struct svga_screen *svgascreen = svga_screen(screen);
svga_screen_cache_cleanup(svgascreen);
pipe_mutex_destroy(svgascreen->swc_mutex);
pipe_mutex_destroy(svgascreen->tex_mutex);
svgascreen->swc->destroy(svgascreen->swc);
svgascreen->sws->destroy(svgascreen->sws);
FREE(svgascreen);
}
/**
* Create a new svga_screen object
*/
struct pipe_screen *
svga_screen_create(struct svga_winsys_screen *sws)
{
struct svga_screen *svgascreen;
struct pipe_screen *screen;
SVGA3dDevCapResult result;
#ifdef DEBUG
SVGA_DEBUG = debug_get_flags_option("SVGA_DEBUG", svga_debug_flags, 0 );
#endif
svgascreen = CALLOC_STRUCT(svga_screen);
if (!svgascreen)
goto error1;
svgascreen->debug.force_level_surface_view =
debug_get_bool_option("SVGA_FORCE_LEVEL_SURFACE_VIEW", FALSE);
svgascreen->debug.force_surface_view =
debug_get_bool_option("SVGA_FORCE_SURFACE_VIEW", FALSE);
svgascreen->debug.force_sampler_view =
debug_get_bool_option("SVGA_FORCE_SAMPLER_VIEW", FALSE);
svgascreen->debug.no_surface_view =
debug_get_bool_option("SVGA_NO_SURFACE_VIEW", FALSE);
svgascreen->debug.no_sampler_view =
debug_get_bool_option("SVGA_NO_SAMPLER_VIEW", FALSE);
screen = &svgascreen->screen;
screen->destroy = svga_destroy_screen;
screen->get_name = svga_get_name;
screen->get_vendor = svga_get_vendor;
screen->get_param = svga_get_param;
screen->get_paramf = svga_get_paramf;
screen->is_format_supported = svga_is_format_supported;
screen->fence_reference = svga_fence_reference;
screen->fence_signalled = svga_fence_signalled;
screen->fence_finish = svga_fence_finish;
svgascreen->sws = sws;
svga_screen_init_texture_functions(screen);
svga_screen_init_buffer_functions(screen);
svgascreen->use_ps30 =
sws->get_cap(sws, SVGA3D_DEVCAP_FRAGMENT_SHADER_VERSION, &result) &&
result.u >= SVGA3DPSVERSION_30 ? TRUE : FALSE;
svgascreen->use_vs30 =
sws->get_cap(sws, SVGA3D_DEVCAP_VERTEX_SHADER_VERSION, &result) &&
result.u >= SVGA3DVSVERSION_30 ? TRUE : FALSE;
#if 1
/* Shader model 2.0 is unsupported at the moment. */
if(!svgascreen->use_ps30 || !svgascreen->use_vs30)
goto error2;
#else
if(debug_get_bool_option("SVGA_NO_SM30", FALSE))
svgascreen->use_vs30 = svgascreen->use_ps30 = FALSE;
#endif
svgascreen->swc = sws->context_create(sws);
if(!svgascreen->swc)
goto error2;
pipe_mutex_init(svgascreen->tex_mutex);
pipe_mutex_init(svgascreen->swc_mutex);
LIST_INITHEAD(&svgascreen->cached_buffers);
svga_screen_cache_init(svgascreen);
return screen;
error2:
FREE(svgascreen);
error1:
return NULL;
}
void svga_screen_flush( struct svga_screen *svgascreen,
struct pipe_fence_handle **pfence )
{
struct pipe_fence_handle *fence = NULL;
SVGA_DBG(DEBUG_PERF, "%s\n", __FUNCTION__);
pipe_mutex_lock(svgascreen->swc_mutex);
svgascreen->swc->flush(svgascreen->swc, &fence);
pipe_mutex_unlock(svgascreen->swc_mutex);
svga_screen_cache_flush(svgascreen, fence);
if(pfence)
*pfence = fence;
else
svgascreen->sws->fence_reference(svgascreen->sws, &fence, NULL);
}
struct svga_winsys_screen *
svga_winsys_screen(struct pipe_screen *screen)
{
return svga_screen(screen)->sws;
}
#ifdef DEBUG
struct svga_screen *
svga_screen(struct pipe_screen *screen)
{
assert(screen);
assert(screen->destroy == svga_destroy_screen);
return (struct svga_screen *)screen;
}
#endif