Merge remote branch 'origin/lp-binning'

Conflicts:
	src/gallium/auxiliary/util/u_dl.c
	src/gallium/auxiliary/util/u_time.h
	src/gallium/drivers/llvmpipe/lp_state_derived.c
	src/gallium/drivers/llvmpipe/lp_state_surface.c
	src/gallium/drivers/llvmpipe/lp_tex_cache.c
	src/gallium/drivers/llvmpipe/lp_tile_cache.c
This commit is contained in:
José Fonseca 2010-02-05 13:48:35 +00:00
commit a1af8eec66
78 changed files with 7187 additions and 3858 deletions

View file

@ -127,6 +127,7 @@ linux-ia64-icc-static \
linux-icc \
linux-icc-static \
linux-llvm \
linux-llvm-debug \
linux-opengl-es \
linux-osmesa \
linux-osmesa-static \

View file

@ -1,5 +1,5 @@
# -*-makefile-*-
# Configuration for Linux and LLVM with debugging info
# Configuration for Linux and LLVM with optimizations
# Builds the llvmpipe gallium driver
include $(TOP)/configs/linux
@ -9,8 +9,10 @@ CONFIG_NAME = linux-llvm
# Add llvmpipe driver
GALLIUM_DRIVERS_DIRS += llvmpipe
OPT_FLAGS = -g -ansi -pedantic
DEFINES += -DDEBUG -DDEBUG_MATH -DGALLIUM_LLVMPIPE -DHAVE_UDIS86
OPT_FLAGS = -O3 -ansi -pedantic
ARCH_FLAGS = -m32 -mmmx -msse -msse2 -mstackrealign
DEFINES += -DNDEBUG -DGALLIUM_LLVMPIPE -DHAVE_UDIS86
# override -std=c99
CFLAGS += -std=gnu99

12
configs/linux-llvm-debug Normal file
View file

@ -0,0 +1,12 @@
# -*-makefile-*-
# Configuration for Linux and LLVM with debugging info
# Builds the llvmpipe gallium driver
include $(TOP)/configs/linux-llvm
CONFIG_NAME = linux-llvm-debug
OPT_FLAGS = -g -ansi -pedantic
DEFINES += -DDEBUG -UNDEBUG

View file

@ -26,6 +26,8 @@
/* Target engine speed: */
const int RPM = 100.0;
static int Win = 0;
/**
* Engine description.
@ -1154,6 +1156,7 @@ OptRotate(void)
static void
OptExit(void)
{
glutDestroyWindow(Win);
exit(0);
}
@ -1323,7 +1326,7 @@ main(int argc, char *argv[])
glutInitWindowSize(WinWidth, WinHeight);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("OpenGL Engine Demo");
Win = glutCreateWindow("OpenGL Engine Demo");
glewInit();
glutReshapeFunc(Reshape);
glutMouseFunc(Mouse);

View file

@ -41,6 +41,7 @@
/* for convolution */
#define FILTER_SIZE 7
static GLint Win;
static GLint WinWidth = 500, WinHeight = 500;
static GLuint CylinderObj = 0;
static GLuint TeapotObj = 0;
@ -214,7 +215,11 @@ static void Key( unsigned char key, int x, int y )
case ' ':
ToggleAnimate();
break;
case 'n':
Idle();
break;
case 27:
glutDestroyWindow(Win);
exit(0);
break;
}
@ -439,7 +444,7 @@ int main( int argc, char *argv[] )
glutInitWindowSize(WinWidth, WinHeight);
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
glutCreateWindow(argv[0] );
Win = glutCreateWindow(argv[0] );
glewInit();
glutReshapeFunc( Reshape );
glutKeyboardFunc( Key );

View file

@ -90,6 +90,8 @@ SOURCES = \
quadstrip-flat.c \
quadstrip.c \
readpixels.c \
sub-tex.c \
tex-quads.c \
tri-alpha.c \
tri-alpha-tex.c \
tri-array-interleaved.c \

View file

@ -70,6 +70,8 @@ progs = [
'quadstrip-cont',
'quadstrip-flat',
'quadstrip',
'sub-tex',
'tex-quads',
'tri-alpha',
'tri-blend-color',
'tri-blend-max',

137
progs/trivial/sub-tex.c Normal file
View file

@ -0,0 +1,137 @@
/**
* Draw a series of textured quads after each quad, use glTexSubImage()
* to change one row of the texture image.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
static GLint Win = 0;
static GLuint Tex = 0;
static void Init(void)
{
fprintf(stderr, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
fflush(stderr);
glGenTextures(1, &Tex);
glBindTexture(GL_TEXTURE_2D, Tex);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
static void Reshape(int width, int height)
{
float ar = (float) width / height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
static void Key(unsigned char key, int x, int y)
{
if (key == 27) {
glDeleteTextures(1, &Tex);
glutDestroyWindow(Win);
exit(1);
}
glutPostRedisplay();
}
static void Draw(void)
{
GLubyte tex[16][16][4];
GLubyte row[16][4];
int i, j;
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
if ((i + j) & 1) {
tex[i][j][0] = 128;
tex[i][j][1] = 128;
tex[i][j][2] = 128;
tex[i][j][3] = 255;
}
else {
tex[i][j][0] = 255;
tex[i][j][1] = 255;
tex[i][j][2] = 255;
tex[i][j][3] = 255;
}
}
}
for (i = 0; i < 16; i++) {
row[i][0] = 255;
row[i][1] = 0;
row[i][2] = 0;
row[i][3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT);
for (i = 0; i < 9; i++) {
glPushMatrix();
glTranslatef(-4.0 + i, 0, 0);
glScalef(0.5, 0.5, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(1,0);
glVertex3f( 0.9, -0.9, 0.0);
glTexCoord2f(1,1);
glVertex3f( 0.9, 0.9, 0.0);
glTexCoord2f(0,1);
glVertex3f(-0.9, 0.9, 0.0);
glTexCoord2f(0,0);
glVertex3f(-0.9, -0.9, 0.0);
glEnd();
glPopMatrix();
/* replace a row of the texture image with red texels */
if (i * 2 < 16)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i*2, 16, 1,
GL_RGBA, GL_UNSIGNED_BYTE, row);
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(900, 200);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
Win = glutCreateWindow(*argv);
if (!Win) {
exit(1);
}
glewInit();
Init();
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutDisplayFunc(Draw);
glutMainLoop();
return 0;
}

143
progs/trivial/tex-quads.c Normal file
View file

@ -0,0 +1,143 @@
/**
* Draw a series of quads, each with a different texture.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#define NUM_TEX 10
static GLint Win = 0;
static GLuint Tex[NUM_TEX];
static void Init(void)
{
int i;
fprintf(stderr, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
fflush(stderr);
glGenTextures(NUM_TEX, Tex);
for (i = 0; i < NUM_TEX; i++) {
glBindTexture(GL_TEXTURE_2D, Tex[i]);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
static void Reshape(int width, int height)
{
float ar = (float) width / height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
static void Key(unsigned char key, int x, int y)
{
if (key == 27) {
glDeleteTextures(NUM_TEX, Tex);
glutDestroyWindow(Win);
exit(1);
}
glutPostRedisplay();
}
static void Draw(void)
{
GLubyte tex[16][16][4];
int t, i, j;
for (t = 0; t < NUM_TEX; t++) {
for (i = 0; i < 16; i++) {
for (j = 0; j < 16; j++) {
if (i < t) {
/* red row */
tex[i][j][0] = 255;
tex[i][j][1] = 0;
tex[i][j][2] = 0;
tex[i][j][3] = 255;
}
else if ((i + j) & 1) {
tex[i][j][0] = 128;
tex[i][j][1] = 128;
tex[i][j][2] = 128;
tex[i][j][3] = 255;
}
else {
tex[i][j][0] = 255;
tex[i][j][1] = 255;
tex[i][j][2] = 255;
tex[i][j][3] = 255;
}
}
}
glBindTexture(GL_TEXTURE_2D, Tex[t]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0,
GL_RGBA, GL_UNSIGNED_BYTE, tex);
}
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT);
for (i = 0; i < NUM_TEX; i++) {
glBindTexture(GL_TEXTURE_2D, Tex[i]);
glPushMatrix();
glTranslatef(-4.0 + i, 0, 0);
glScalef(0.5, 0.5, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(1,0);
glVertex3f( 0.9, -0.9, 0.0);
glTexCoord2f(1,1);
glVertex3f( 0.9, 0.9, 0.0);
glTexCoord2f(0,1);
glVertex3f(-0.9, 0.9, 0.0);
glTexCoord2f(0,0);
glVertex3f(-0.9, -0.9, 0.0);
glEnd();
glPopMatrix();
}
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(900, 200);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
Win = glutCreateWindow(*argv);
if (!Win) {
exit(1);
}
glewInit();
Init();
glutReshapeFunc(Reshape);
glutKeyboardFunc(Key);
glutDisplayFunc(Draw);
glutMainLoop();
return 0;
}

View file

@ -31,10 +31,14 @@
#define CI_OFFSET_1 16
#define CI_OFFSET_2 32
GLint Width = 250, Height = 250;
GLint Width = 300, Height = 300;
GLenum doubleBuffer;
/* scissor bounds */
static GLint Left, Right, Bottom, Top;
static void Init(void)
{
fprintf(stderr, "GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
@ -47,26 +51,57 @@ static void Init(void)
static void Reshape(int width, int height)
{
glViewport(0, 0, (GLint)width, (GLint)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -0.5, 1000.0);
glMatrixMode(GL_MODELVIEW);
Width = width;
Height = height;
Left = Width / 4;
Right = Width * 3 / 4;
Bottom = Height / 4;
Top = Height * 3 / 4;
}
static void Key(unsigned char key, int x, int y)
{
int step = 2;
switch (key) {
case 'l':
Left -= step;
break;
case 'L':
Left += step;
break;
case 'r':
Right -= step;
break;
case 'R':
Right += step;
break;
case 'b':
Bottom -= step;
break;
case 'B':
Bottom += step;
break;
case 't':
Top -= step;
break;
case 'T':
Top += step;
break;
case 27:
exit(1);
default:
;
}
switch (key) {
case 27:
exit(1);
default:
break;
}
glutPostRedisplay();
glutPostRedisplay();
}
static void Draw(void)
@ -82,7 +117,8 @@ static void Draw(void)
glVertex3f(-0.9, 0.0, -30.0);
glEnd();
glScissor(Width / 4, Height / 4, Width / 2, Height / 2);
printf("Scissor %d, %d .. %d, %d\n", Left, Bottom, Right, Top);
glScissor(Left, Bottom, Right-Left, Top-Bottom);
glEnable(GL_SCISSOR_TEST);
glBegin(GL_TRIANGLES);

View file

@ -69,6 +69,8 @@ static void Key(unsigned char key, int x, int y)
static void Draw(void)
{
float z = 1.0;
glClearColor(0.0, 0.0, 1.0, 0.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -77,15 +79,21 @@ static void Draw(void)
glBegin(GL_TRIANGLES);
glColor3f(0,0,.7);
glVertex3f( 0.9, -0.9, 1.0);
glVertex3f( 0.9, -0.9, z);
glColor3f(.8,0,0);
glVertex3f( 0.9, 0.9, 1.0);
glVertex3f( 0.9, 0.9, z);
glColor3f(0,.9,0);
glVertex3f(-0.9, 0.0, 1.0);
glVertex3f(-0.9, 0.0, z);
glEnd();
glFlush();
{
GLfloat z;
glReadPixels(125, 125, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
printf("Z at (125, 125) = %f\n", z);
}
if (doubleBuffer) {
glutSwapBuffers();
}

View file

@ -27,7 +27,8 @@
/**
* @file
*
* Thread, mutex, condition var and thread-specific data functions.
* Thread, mutex, condition variable, barrier, semaphore and
* thread-specific data functions.
*/
@ -46,6 +47,8 @@
#define PIPE_THREAD_HAVE_CONDVAR
/* pipe_thread
*/
typedef pthread_t pipe_thread;
#define PIPE_THREAD_ROUTINE( name, param ) \
@ -69,8 +72,10 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
return pthread_detach( thread );
}
/* pipe_mutex
*/
typedef pthread_mutex_t pipe_mutex;
typedef pthread_cond_t pipe_condvar;
#define pipe_static_mutex(mutex) \
static pipe_mutex mutex = PTHREAD_MUTEX_INITIALIZER
@ -87,6 +92,11 @@ typedef pthread_cond_t pipe_condvar;
#define pipe_mutex_unlock(mutex) \
(void) pthread_mutex_unlock(&(mutex))
/* pipe_condvar
*/
typedef pthread_cond_t pipe_condvar;
#define pipe_static_condvar(mutex) \
static pipe_condvar mutex = PTHREAD_COND_INITIALIZER
@ -106,10 +116,32 @@ typedef pthread_cond_t pipe_condvar;
pthread_cond_broadcast(&(cond))
/* pipe_barrier
*/
typedef pthread_barrier_t pipe_barrier;
static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
{
pthread_barrier_init(barrier, NULL, count);
}
static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
{
pthread_barrier_destroy(barrier);
}
static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
{
pthread_barrier_wait(barrier);
}
#elif defined(PIPE_SUBSYSTEM_WINDOWS_USER)
#include <windows.h>
/* pipe_thread
*/
typedef HANDLE pipe_thread;
#define PIPE_THREAD_ROUTINE( name, param ) \
@ -135,6 +167,9 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
return -1;
}
/* pipe_mutex
*/
typedef CRITICAL_SECTION pipe_mutex;
#define pipe_static_mutex(mutex) \
@ -152,15 +187,48 @@ typedef CRITICAL_SECTION pipe_mutex;
#define pipe_mutex_unlock(mutex) \
LeaveCriticalSection(&mutex)
/* XXX: dummy definitions, make it compile */
/* pipe_condvar (XXX FIX THIS)
*/
typedef unsigned pipe_condvar;
#define pipe_condvar_init(condvar) \
(void) condvar
#define pipe_condvar_init(cond) \
(void) cond
#define pipe_condvar_destroy(cond) \
(void) cond
#define pipe_condvar_wait(cond, mutex) \
(void) cond; (void) mutex
#define pipe_condvar_signal(cond) \
(void) cond
#define pipe_condvar_broadcast(cond) \
(void) cond
/* pipe_barrier (XXX FIX THIS)
*/
typedef unsigned pipe_barrier;
static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
{
/* XXX we could implement barriers with a mutex and condition var */
assert(0);
}
static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
{
assert(0);
}
static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
{
assert(0);
}
#define pipe_condvar_broadcast(condvar) \
(void) condvar
#else
@ -188,6 +256,7 @@ static INLINE int pipe_thread_destroy( pipe_thread thread )
typedef unsigned pipe_mutex;
typedef unsigned pipe_condvar;
typedef unsigned pipe_barrier;
#define pipe_static_mutex(mutex) \
static pipe_mutex mutex = 0
@ -223,9 +292,77 @@ typedef unsigned pipe_condvar;
(void) condvar
static INLINE void pipe_barrier_init(pipe_barrier *barrier, unsigned count)
{
/* XXX we could implement barriers with a mutex and condition var */
assert(0);
}
static INLINE void pipe_barrier_destroy(pipe_barrier *barrier)
{
assert(0);
}
static INLINE void pipe_barrier_wait(pipe_barrier *barrier)
{
assert(0);
}
#endif /* PIPE_OS_? */
/*
* Semaphores
*/
typedef struct
{
pipe_mutex mutex;
pipe_condvar cond;
int counter;
} pipe_semaphore;
static INLINE void
pipe_semaphore_init(pipe_semaphore *sema, int init_val)
{
pipe_mutex_init(sema->mutex);
pipe_condvar_init(sema->cond);
sema->counter = init_val;
}
static INLINE void
pipe_semaphore_destroy(pipe_semaphore *sema)
{
pipe_mutex_destroy(sema->mutex);
pipe_condvar_destroy(sema->cond);
}
/** Signal/increment semaphore counter */
static INLINE void
pipe_semaphore_signal(pipe_semaphore *sema)
{
pipe_mutex_lock(sema->mutex);
sema->counter++;
pipe_condvar_signal(sema->cond);
pipe_mutex_unlock(sema->mutex);
}
/** Wait for semaphore counter to be greater than zero */
static INLINE void
pipe_semaphore_wait(pipe_semaphore *sema)
{
pipe_mutex_lock(sema->mutex);
while (sema->counter <= 0) {
pipe_condvar_wait(sema->cond, sema->mutex);
}
sema->counter--;
pipe_mutex_unlock(sema->mutex);
}
/*
* Thread-specific data.

View file

@ -440,6 +440,14 @@ const char *u_prim_name( unsigned prim )
#ifdef DEBUG
/**
* Dump an image to a .raw or .ppm file (depends on OS).
* \param format PIPE_FORMAT_x
* \param cpp bytes per pixel
* \param width width in pixels
* \param height height in pixels
* \param stride row stride in bytes
*/
void debug_dump_image(const char *prefix,
unsigned format, unsigned cpp,
unsigned width, unsigned height,
@ -481,6 +489,52 @@ void debug_dump_image(const char *prefix,
}
EngUnmapFile(iFile);
#elif defined(PIPE_OS_UNIX)
/* write a ppm file */
char filename[256];
FILE *f;
util_snprintf(filename, sizeof(filename), "%s.ppm", prefix);
f = fopen(filename, "w");
if (f) {
int i, x, y;
int r, g, b;
const uint8_t *ptr = (uint8_t *) data;
/* XXX this is a hack */
switch (format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
r = 2;
g = 1;
b = 0;
break;
default:
r = 0;
g = 1;
b = 1;
}
fprintf(f, "P6\n");
fprintf(f, "# ppm-file created by osdemo.c\n");
fprintf(f, "%i %i\n", width, height);
fprintf(f, "255\n");
fclose(f);
f = fopen(filename, "ab"); /* reopen in binary append mode */
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
i = y * stride + x * cpp;
fputc(ptr[i + r], f); /* write red */
fputc(ptr[i + g], f); /* write green */
fputc(ptr[i + b], f); /* write blue */
}
}
fclose(f);
}
else {
fprintf(stderr, "Can't open %s for writing\n", filename);
}
#endif
}
@ -521,6 +575,27 @@ error:
}
void debug_dump_texture(const char *prefix,
struct pipe_texture *texture)
{
struct pipe_surface *surface;
struct pipe_screen *screen;
if (!texture)
return;
screen = texture->screen;
/* XXX for now, just dump image for face=0, level=0 */
surface = screen->get_tex_surface(screen, texture, 0, 0, 0,
PIPE_TEXTURE_USAGE_SAMPLER);
if (surface) {
debug_dump_surface(prefix, surface);
screen->tex_surface_destroy(surface);
}
}
#pragma pack(push,2)
struct bmp_file_header {
uint16_t bfType;

View file

@ -314,6 +314,8 @@ debug_memory_end(unsigned long beginning);
#ifdef DEBUG
struct pipe_surface;
struct pipe_transfer;
struct pipe_texture;
void debug_dump_image(const char *prefix,
unsigned format, unsigned cpp,
unsigned width, unsigned height,
@ -321,6 +323,8 @@ void debug_dump_image(const char *prefix,
const void *data);
void debug_dump_surface(const char *prefix,
struct pipe_surface *surface);
void debug_dump_texture(const char *prefix,
struct pipe_texture *texture);
void debug_dump_surface_bmp(const char *filename,
struct pipe_surface *surface);
void debug_dump_transfer_bmp(const char *filename,

View file

@ -53,11 +53,22 @@ void util_ringbuffer_destroy( struct util_ringbuffer *ring )
FREE(ring);
}
/**
* Return number of free entries in the ring
*/
static INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
{
return (ring->tail - (ring->head + 1)) & ring->mask;
}
/**
* Is the ring buffer empty?
*/
static INLINE boolean util_ringbuffer_empty( const struct util_ringbuffer *ring )
{
return util_ringbuffer_space(ring) == ring->mask;
}
void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
const struct util_packet *packet )
{
@ -67,6 +78,10 @@ void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
*/
pipe_mutex_lock(ring->mutex);
/* make sure we don't request an impossible amount of space
*/
assert(packet->dwords <= ring->mask);
/* Wait for free space:
*/
while (util_ringbuffer_space(ring) < packet->dwords)
@ -104,14 +119,14 @@ enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
*/
pipe_mutex_lock(ring->mutex);
/* Wait for free space:
/* Get next ring entry:
*/
if (wait) {
while (util_ringbuffer_space(ring) == 0)
while (util_ringbuffer_empty(ring))
pipe_condvar_wait(ring->change, ring->mutex);
}
else {
if (util_ringbuffer_space(ring) == 0) {
if (util_ringbuffer_empty(ring)) {
ret = PIPE_ERROR_OUT_OF_MEMORY;
goto out;
}

View file

@ -37,6 +37,7 @@
#include "pipe/p_defines.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_surface.h"
@ -111,3 +112,73 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
pipe_texture_reference(&texture, NULL);
}
/**
* Compare pipe_framebuffer_state objects.
* \return TRUE if same, FALSE if different
*/
boolean
util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
const struct pipe_framebuffer_state *src)
{
unsigned i;
if (dst->width != src->width ||
dst->height != src->height)
return FALSE;
for (i = 0; i < Elements(src->cbufs); i++) {
if (dst->cbufs[i] != src->cbufs[i]) {
return FALSE;
}
}
if (dst->nr_cbufs != src->nr_cbufs) {
return FALSE;
}
if (dst->zsbuf != src->zsbuf) {
return FALSE;
}
return TRUE;
}
/**
* Copy framebuffer state from src to dst, updating refcounts.
*/
void
util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
const struct pipe_framebuffer_state *src)
{
unsigned i;
dst->width = src->width;
dst->height = src->height;
for (i = 0; i < Elements(src->cbufs); i++) {
pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]);
}
dst->nr_cbufs = src->nr_cbufs;
pipe_surface_reference(&dst->zsbuf, src->zsbuf);
}
void
util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb)
{
unsigned i;
for (i = 0; i < fb->nr_cbufs; i++) {
pipe_surface_reference(&fb->cbufs[i], NULL);
}
pipe_surface_reference(&fb->zsbuf, NULL);
fb->width = fb->height = 0;
fb->nr_cbufs = 0;
}

View file

@ -30,11 +30,7 @@
#include "pipe/p_compiler.h"
struct pipe_screen;
struct pipe_texture;
struct pipe_surface;
#include "pipe/p_state.h"
/**
@ -66,4 +62,17 @@ util_destroy_rgba_surface(struct pipe_texture *texture,
struct pipe_surface *surface);
extern boolean
util_framebuffer_state_equal(const struct pipe_framebuffer_state *dst,
const struct pipe_framebuffer_state *src);
extern void
util_copy_framebuffer_state(struct pipe_framebuffer_state *dst,
const struct pipe_framebuffer_state *src);
extern void
util_unreference_framebuffer_state(struct pipe_framebuffer_state *fb);
#endif /* U_SURFACE_H */

View file

@ -67,6 +67,9 @@ util_time_get(struct util_time *t)
}
/**
* Return t2 = t1 + usecs
*/
PIPE_DEPRECATED
static INLINE void
util_time_add(const struct util_time *t1,
@ -77,6 +80,9 @@ util_time_add(const struct util_time *t1,
}
/**
* Return difference between times, in microseconds
*/
PIPE_DEPRECATED
static INLINE int64_t
util_time_diff(const struct util_time *t1,
@ -105,6 +111,9 @@ _util_time_compare(const struct util_time *t1,
}
/**
* Returns non-zero when the timeout expires.
*/
PIPE_DEPRECATED
static INLINE boolean
util_time_timeout(const struct util_time *start,
@ -115,6 +124,9 @@ util_time_timeout(const struct util_time *start,
}
/**
* Return current time in microseconds
*/
PIPE_DEPRECATED
static INLINE int64_t
util_time_micros(void)

View file

@ -3,7 +3,7 @@ include $(TOP)/configs/current
LIBNAME = llvmpipe
CFLAGS += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
DEFINES += -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
C_SOURCES = \
lp_bld_alpha.c \
@ -33,12 +33,21 @@ C_SOURCES = \
lp_clear.c \
lp_context.c \
lp_draw_arrays.c \
lp_fence.c \
lp_flush.c \
lp_jit.c \
lp_prim_vbuf.c \
lp_setup.c \
lp_perf.c \
lp_query.c \
lp_rast.c \
lp_rast_tri.c \
lp_scene.c \
lp_scene_queue.c \
lp_screen.c \
lp_setup.c \
lp_setup_line.c \
lp_setup_point.c \
lp_setup_tri.c \
lp_setup_vbuf.c \
lp_state_blend.c \
lp_state_clip.c \
lp_state_derived.c \
@ -49,10 +58,8 @@ C_SOURCES = \
lp_state_vertex.c \
lp_state_vs.c \
lp_surface.c \
lp_tex_cache.c \
lp_tex_sample_llvm.c \
lp_texture.c \
lp_tile_cache.c \
lp_tile_soa.c
CPP_SOURCES = \
@ -62,3 +69,8 @@ include ../../Makefile.template
lp_tile_soa.c: lp_tile_soa.py ../../auxiliary/util/u_format_parse.py ../../auxiliary/util/u_format_access.py ../../auxiliary/util/u_format.csv
python lp_tile_soa.py ../../auxiliary/util/u_format.csv > $@
# to make a .s file to inspect assembly code
.c.s:
$(CC) -S $(INCLUDES) $(DEFINES) $(CFLAGS) $(LIBRARY_DEFINES) $<

View file

@ -32,16 +32,16 @@ llvmpipe = env.ConvenienceLibrary(
'lp_bld_depth.c',
'lp_bld_flow.c',
'lp_bld_format_aos.c',
'lp_bld_format_query.c',
'lp_bld_format_query.c',
'lp_bld_format_soa.c',
'lp_bld_interp.c',
'lp_bld_intr.c',
'lp_bld_logic.c',
'lp_bld_misc.cpp',
'lp_bld_pack.c',
'lp_bld_sample.c',
'lp_bld_pack.c',
'lp_bld_sample.c',
'lp_bld_sample_soa.c',
'lp_bld_struct.c',
'lp_bld_logic.c',
'lp_bld_swizzle.c',
'lp_bld_tgsi_soa.c',
'lp_bld_type.c',
@ -49,12 +49,21 @@ llvmpipe = env.ConvenienceLibrary(
'lp_clear.c',
'lp_context.c',
'lp_draw_arrays.c',
'lp_fence.c',
'lp_flush.c',
'lp_jit.c',
'lp_prim_vbuf.c',
'lp_setup.c',
'lp_perf.c',
'lp_query.c',
'lp_rast.c',
'lp_rast_tri.c',
'lp_scene.c',
'lp_scene_queue.c',
'lp_screen.c',
'lp_setup.c',
'lp_setup_line.c',
'lp_setup_point.c',
'lp_setup_tri.c',
'lp_setup_vbuf.c',
'lp_state_blend.c',
'lp_state_clip.c',
'lp_state_derived.c',
@ -65,10 +74,8 @@ llvmpipe = env.ConvenienceLibrary(
'lp_state_vertex.c',
'lp_state_vs.c',
'lp_surface.c',
'lp_tex_cache.c',
'lp_tex_sample_llvm.c',
'lp_texture.c',
'lp_tile_cache.c',
'lp_tile_soa.c',
])

View file

@ -56,6 +56,7 @@
#include "lp_bld_intr.h"
#include "lp_bld_logic.h"
#include "lp_bld_pack.h"
#include "lp_bld_debug.h"
#include "lp_bld_arit.h"
@ -628,7 +629,7 @@ lp_build_abs(struct lp_build_context *bld,
if(type.floating) {
/* Mask out the sign bit */
LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
unsigned long absMask = ~(1 << (type.width - 1));
unsigned long long absMask = ~(1ULL << (type.width - 1));
LLVMValueRef mask = lp_build_int_const_scalar(type, ((unsigned long long) absMask));
a = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
a = LLVMBuildAnd(bld->builder, a, mask, "");
@ -873,6 +874,9 @@ lp_build_iround(struct lp_build_context *bld,
}
/**
* Convert float[] to int[] with floor().
*/
LLVMValueRef
lp_build_ifloor(struct lp_build_context *bld,
LLVMValueRef a)
@ -899,6 +903,7 @@ lp_build_ifloor(struct lp_build_context *bld,
sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
sign = LLVMBuildAnd(bld->builder, sign, mask, "");
sign = LLVMBuildAShr(bld->builder, sign, lp_build_int_const_scalar(type, type.width - 1), "");
lp_build_name(sign, "floor.sign");
/* offset = -0.99999(9)f */
offset = lp_build_const_scalar(type, -(double)(((unsigned long long)1 << mantissa) - 1)/((unsigned long long)1 << mantissa));
@ -907,11 +912,14 @@ lp_build_ifloor(struct lp_build_context *bld,
/* offset = a < 0 ? -0.99999(9)f : 0.0f */
offset = LLVMBuildAnd(bld->builder, offset, sign, "");
offset = LLVMBuildBitCast(bld->builder, offset, vec_type, "");
lp_build_name(offset, "floor.offset");
res = LLVMBuildAdd(bld->builder, a, offset, "");
lp_build_name(res, "floor.res");
}
res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, "");
lp_build_name(res, "floor");
return res;
}

View file

@ -123,6 +123,10 @@ lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
res = LLVMBuildShl(builder, res, lp_build_int_const_scalar(src_type, shift), "");
/* TODO: Fill in the empty lower bits for additional precision? */
/* YES: this fixes progs/trivial/tri-z-eq.c.
* Otherwise vertex Z=1.0 values get converted to something like
* 0xfffffb00 and the test for equality with 0xffffffff fails.
*/
#if 0
{
LLVMValueRef msb;

View file

@ -41,13 +41,13 @@
#define LP_BUILD_FLOW_MAX_VARIABLES 32
#define LP_BUILD_FLOW_MAX_DEPTH 32
/**
* Enumeration of all possible flow constructs.
*/
enum lp_build_flow_construct_kind {
lP_BUILD_FLOW_SCOPE,
LP_BUILD_FLOW_SKIP
LP_BUILD_FLOW_SCOPE,
LP_BUILD_FLOW_SKIP,
LP_BUILD_FLOW_IF
};
@ -73,7 +73,21 @@ struct lp_build_flow_skip
/** Number of variables declared at the beginning */
unsigned num_variables;
LLVMValueRef *phi;
LLVMValueRef *phi; /**< array [num_variables] */
};
/**
* if/else/endif.
*/
struct lp_build_flow_if
{
unsigned num_variables;
LLVMValueRef *phi; /**< array [num_variables] */
LLVMValueRef condition;
LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
};
@ -84,6 +98,7 @@ union lp_build_flow_construct_data
{
struct lp_build_flow_scope scope;
struct lp_build_flow_skip skip;
struct lp_build_flow_if ifthen;
};
@ -145,6 +160,10 @@ lp_build_flow_destroy(struct lp_build_flow_context *flow)
}
/**
* Begin/push a new flow control construct, such as a loop, skip block
* or variable scope.
*/
static union lp_build_flow_construct_data *
lp_build_flow_push(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@ -158,6 +177,10 @@ lp_build_flow_push(struct lp_build_flow_context *flow,
}
/**
* Return the current/top flow control construct on the stack.
* \param kind the expected type of the top-most construct
*/
static union lp_build_flow_construct_data *
lp_build_flow_peek(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@ -174,6 +197,10 @@ lp_build_flow_peek(struct lp_build_flow_context *flow,
}
/**
* End/pop the current/top flow control construct on the stack.
* \param kind the expected type of the top-most construct
*/
static union lp_build_flow_construct_data *
lp_build_flow_pop(struct lp_build_flow_context *flow,
enum lp_build_flow_construct_kind kind)
@ -200,7 +227,7 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_push(flow, lP_BUILD_FLOW_SCOPE)->scope;
scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@ -213,11 +240,11 @@ lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
*
* A variable is a named entity which can have different LLVMValueRef's at
* different points of the program. This is relevant for control flow because
* when there are mutiple branches to a same location we need to replace
* when there are multiple branches to a same location we need to replace
* the variable's value with a Phi function as explained in
* http://en.wikipedia.org/wiki/Static_single_assignment_form .
*
* We keep track of variables by keeping around a pointer to where their
* We keep track of variables by keeping around a pointer to where they're
* current.
*
* There are a few cautions to observe:
@ -241,7 +268,7 @@ lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_peek(flow, lP_BUILD_FLOW_SCOPE)->scope;
scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@ -263,7 +290,7 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
{
struct lp_build_flow_scope *scope;
scope = &lp_build_flow_pop(flow, lP_BUILD_FLOW_SCOPE)->scope;
scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
if(!scope)
return;
@ -277,27 +304,47 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
}
/**
* Note: this function has no dependencies on the flow code and could
* be used elsewhere.
*/
static LLVMBasicBlockRef
lp_build_flow_insert_block(struct lp_build_flow_context *flow)
lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
{
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef next_block;
LLVMBasicBlockRef new_block;
current_block = LLVMGetInsertBlock(flow->builder);
/* get current basic block */
current_block = LLVMGetInsertBlock(builder);
/* check if there's another block after this one */
next_block = LLVMGetNextBasicBlock(current_block);
if(next_block) {
new_block = LLVMInsertBasicBlock(next_block, "");
if (next_block) {
/* insert the new block before the next block */
new_block = LLVMInsertBasicBlock(next_block, name);
}
else {
/* append new block after current block */
LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
new_block = LLVMAppendBasicBlock(function, "");
new_block = LLVMAppendBasicBlock(function, name);
}
return new_block;
}
static LLVMBasicBlockRef
lp_build_flow_insert_block(struct lp_build_flow_context *flow)
{
return lp_build_insert_new_block(flow->builder, "");
}
/**
* Begin a "skip" block. Inside this block we can test a condition and
* skip to the end of the block if the condition is false.
*/
void
lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
{
@ -309,13 +356,16 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
if(!skip)
return;
/* create new basic block */
skip->block = lp_build_flow_insert_block(flow);
skip->num_variables = flow->num_variables;
if(!skip->num_variables) {
skip->phi = NULL;
return;
}
/* Allocate a Phi node for each variable in this skip scope */
skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
if(!skip->phi) {
skip->num_variables = 0;
@ -325,6 +375,7 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, skip->block);
/* create a Phi node for each variable */
for(i = 0; i < skip->num_variables; ++i)
skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
@ -332,6 +383,10 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
}
/**
* Insert code to test a condition and branch to the end of the current
* skip block if the condition is true.
*/
void
lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
LLVMValueRef cond)
@ -349,15 +404,17 @@ lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
new_block = lp_build_flow_insert_block(flow);
/* for each variable, update the Phi node with a (variable, block) pair */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
}
/* if cond is true, goto skip->block, else goto new_block */
LLVMBuildCondBr(flow->builder, cond, skip->block, new_block);
LLVMPositionBuilderAtEnd(flow->builder, new_block);
}
}
void
@ -373,12 +430,14 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
current_block = LLVMGetInsertBlock(flow->builder);
/* add (variable, block) tuples to the phi nodes */
for(i = 0; i < skip->num_variables; ++i) {
assert(*flow->variables[i]);
LLVMAddIncoming(skip->phi[i], flow->variables[i], &current_block, 1);
*flow->variables[i] = skip->phi[i];
}
/* goto block */
LLVMBuildBr(flow->builder, skip->block);
LLVMPositionBuilderAtEnd(flow->builder, skip->block);
@ -386,22 +445,34 @@ lp_build_flow_skip_end(struct lp_build_flow_context *flow)
}
/**
* Check if the mask predicate is zero. If so, jump to the end of the block.
*/
static void
lp_build_mask_check(struct lp_build_mask_context *mask)
{
LLVMBuilderRef builder = mask->flow->builder;
LLVMValueRef cond;
/* cond = (mask == 0) */
cond = LLVMBuildICmp(builder,
LLVMIntEQ,
LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
LLVMConstNull(mask->reg_type),
"");
/* if cond, goto end of block */
lp_build_flow_skip_cond_break(mask->flow, cond);
}
/**
* Begin a section of code which is predicated on a mask.
* \param mask the mask context, initialized here
* \param flow the flow context
* \param type the type of the mask
* \param value storage for the mask
*/
void
lp_build_mask_begin(struct lp_build_mask_context *mask,
struct lp_build_flow_context *flow,
@ -422,6 +493,11 @@ lp_build_mask_begin(struct lp_build_mask_context *mask,
}
/**
* Update boolean mask with given value (bitwise AND).
* Typically used to update the quad's pixel alive/killed mask
* after depth testing, alpha testing, TGSI_OPCODE_KIL, etc.
*/
void
lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value)
@ -432,6 +508,9 @@ lp_build_mask_update(struct lp_build_mask_context *mask,
}
/**
* End section of code which is predicated on a mask.
*/
LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask)
{
@ -491,3 +570,188 @@ lp_build_loop_end(LLVMBuilderRef builder,
LLVMPositionBuilderAtEnd(builder, after_block);
}
/*
Example of if/then/else building:
int x;
if (cond) {
x = 1 + 2;
}
else {
x = 2 + 3;
}
Is built with:
LLVMValueRef x = LLVMGetUndef(); // or something else
flow = lp_build_flow_create(builder);
lp_build_flow_scope_begin(flow);
// x needs a phi node
lp_build_flow_scope_declare(flow, &x);
lp_build_if(ctx, flow, builder, cond);
x = LLVMAdd(1, 2);
lp_build_else(ctx);
x = LLVMAdd(2, 3);
lp_build_endif(ctx);
lp_build_flow_scope_end(flow);
lp_build_flow_destroy(flow);
*/
/**
* Begin an if/else/endif construct.
*/
void
lp_build_if(struct lp_build_if_state *ctx,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder,
LLVMValueRef condition)
{
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
struct lp_build_flow_if *ifthen;
unsigned i;
memset(ctx, 0, sizeof(*ctx));
ctx->builder = builder;
ctx->flow = flow;
/* push/create new scope */
ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
ifthen->num_variables = flow->num_variables;
ifthen->condition = condition;
ifthen->entry_block = block;
/* create a Phi node for each variable in this flow scope */
ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
if (!ifthen->phi) {
ifthen->num_variables = 0;
return;
}
/* create endif/merge basic block for the phi functions */
ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);
/* create a phi node for each variable */
for (i = 0; i < flow->num_variables; i++) {
ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
/* add add the initial value of the var from the entry block */
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->entry_block, 1);
}
/* create/insert true_block before merge_block */
ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
/* successive code goes into the true block */
LLVMPositionBuilderAtEnd(builder, ifthen->true_block);
}
/**
* Begin else-part of a conditional
*/
void
lp_build_else(struct lp_build_if_state *ctx)
{
struct lp_build_flow_context *flow = ctx->flow;
struct lp_build_flow_if *ifthen;
unsigned i;
ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
/* for each variable, update the Phi node with a (variable, block) pair */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
}
/* create/insert false_block before the merge block */
ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
/* successive code goes into the else block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
}
/**
* End a conditional.
*/
void
lp_build_endif(struct lp_build_if_state *ctx)
{
struct lp_build_flow_context *flow = ctx->flow;
struct lp_build_flow_if *ifthen;
unsigned i;
ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
if (ifthen->false_block) {
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
/* for each variable, update the Phi node with a (variable, block) pair */
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->false_block, 1);
/* replace the variable ref with the phi function */
*flow->variables[i] = ifthen->phi[i];
}
}
else {
/* no else clause */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
for (i = 0; i < flow->num_variables; i++) {
assert(*flow->variables[i]);
LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
/* replace the variable ref with the phi function */
*flow->variables[i] = ifthen->phi[i];
}
}
FREE(ifthen->phi);
/***
*** Now patch in the various branch instructions.
***/
/* Insert the conditional branch instruction at the end of entry_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block);
if (ifthen->false_block) {
/* we have an else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition,
ifthen->true_block, ifthen->false_block);
}
else {
/* no else clause */
LLVMBuildCondBr(ctx->builder, ifthen->condition,
ifthen->true_block, ifthen->merge_block);
}
/* Append an unconditional Br(anch) instruction on the true_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
LLVMBuildBr(ctx->builder, ifthen->merge_block);
if (ifthen->false_block) {
/* Append an unconditional Br(anch) instruction on the false_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
LLVMBuildBr(ctx->builder, ifthen->merge_block);
}
/* Resume building code at end of the ifthen->merge_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
}

View file

@ -126,4 +126,26 @@ lp_build_loop_end(LLVMBuilderRef builder,
struct lp_build_if_state
{
LLVMBuilderRef builder;
struct lp_build_flow_context *flow;
};
void
lp_build_if(struct lp_build_if_state *ctx,
struct lp_build_flow_context *flow,
LLVMBuilderRef builder,
LLVMValueRef condition);
void
lp_build_else(struct lp_build_if_state *ctx);
void
lp_build_endif(struct lp_build_if_state *ctx);
#endif /* !LP_BLD_FLOW_H */

View file

@ -45,6 +45,36 @@
#include "lp_bld_interp.h"
/*
* The shader JIT function operates on blocks of quads.
* Each block has 2x2 quads and each quad has 2x2 pixels.
*
* We iterate over the quads in order 0, 1, 2, 3:
*
* #################
* # | # | #
* #---0---#---1---#
* # | # | #
* #################
* # | # | #
* #---2---#---3---#
* # | # | #
* #################
*
* Within each quad, we have four pixels which are represented in SOA
* order:
*
* #########
* # 0 | 1 #
* #---+---#
* # 2 | 3 #
* #########
*
* So the green channel (for example) of the four pixels is stored in
* a single vector register: {g0, g1, g2, g3}.
*/
static void
attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix)
{
@ -55,6 +85,10 @@ attrib_name(LLVMValueRef val, unsigned attrib, unsigned chan, const char *suffix
}
/**
* Initialize the bld->a0, dadx, dady fields. This involves fetching
* those values from the arrays which are passed into the JIT function.
*/
static void
coeffs_init(struct lp_build_interp_soa_context *bld,
LLVMValueRef a0_ptr,
@ -91,7 +125,7 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
case TGSI_INTERPOLATE_CONSTANT:
a0 = LLVMBuildLoad(builder, LLVMBuildGEP(builder, a0_ptr, &index, 1, ""), "");
a0 = lp_build_broadcast_scalar(&bld->base, a0);
attrib_name(a0, attrib, chan, ".dady");
attrib_name(a0, attrib, chan, ".a0");
break;
default:
@ -109,29 +143,12 @@ coeffs_init(struct lp_build_interp_soa_context *bld,
/**
* Multiply the dadx and dady with the xstep and ystep respectively.
* Emit LLVM code to compute the fragment shader input attribute values.
* For example, for a color input, we'll compute red, green, blue and alpha
* values for the four pixels in a quad.
* Recall that we're operating on 4-element vectors so each arithmetic
* operation is operating on the four pixels in a quad.
*/
static void
coeffs_update(struct lp_build_interp_soa_context *bld)
{
unsigned attrib;
unsigned chan;
for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
unsigned mask = bld->mask[attrib];
unsigned mode = bld->mode[attrib];
if (mode != TGSI_INTERPOLATE_CONSTANT) {
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
if(mask & (1 << chan)) {
bld->dadx[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dadx[attrib][chan], bld->xstep);
bld->dady[attrib][chan] = lp_build_mul_imm(&bld->base, bld->dady[attrib][chan], bld->ystep);
}
}
}
}
}
static void
attribs_init(struct lp_build_interp_soa_context *bld)
{
@ -154,7 +171,9 @@ attribs_init(struct lp_build_interp_soa_context *bld)
res = a0;
if (mode != TGSI_INTERPOLATE_CONSTANT) {
/* res = res + x * dadx */
res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, x, dadx));
/* res = res + y * dady */
res = lp_build_add(&bld->base, res, lp_build_mul(&bld->base, y, dady));
}
@ -178,13 +197,19 @@ attribs_init(struct lp_build_interp_soa_context *bld)
}
/**
* Increment the shader input attribute values.
* This is called when we move from one quad to the next.
*/
static void
attribs_update(struct lp_build_interp_soa_context *bld)
attribs_update(struct lp_build_interp_soa_context *bld, int quad_index)
{
LLVMValueRef oow = NULL;
unsigned attrib;
unsigned chan;
assert(quad_index < 4);
for(attrib = 0; attrib < bld->num_attribs; ++attrib) {
unsigned mask = bld->mask[attrib];
unsigned mode = bld->mode[attrib];
@ -198,13 +223,21 @@ attribs_update(struct lp_build_interp_soa_context *bld)
res = bld->attribs_pre[attrib][chan];
if(bld->xstep)
if (quad_index == 1 || quad_index == 3) {
/* top-right or bottom-right quad */
/* build res = res + dadx + dadx */
res = lp_build_add(&bld->base, res, dadx);
res = lp_build_add(&bld->base, res, dadx);
}
if(bld->ystep)
if (quad_index == 2 || quad_index == 3) {
/* bottom-left or bottom-right quad */
/* build res = res + dady + dady */
res = lp_build_add(&bld->base, res, dady);
res = lp_build_add(&bld->base, res, dady);
}
bld->attribs_pre[attrib][chan] = res;
//XXX bld->attribs_pre[attrib][chan] = res;
if (mode == TGSI_INTERPOLATE_PERSPECTIVE) {
LLVMValueRef w = bld->pos[3];
@ -242,17 +275,32 @@ pos_init(struct lp_build_interp_soa_context *bld,
}
/**
* Update quad position values when moving to the next quad.
*/
static void
pos_update(struct lp_build_interp_soa_context *bld)
pos_update(struct lp_build_interp_soa_context *bld, int quad_index)
{
LLVMValueRef x = bld->attribs[0][0];
LLVMValueRef y = bld->attribs[0][1];
const int xstep = 2, ystep = 2;
if(bld->xstep)
x = lp_build_add(&bld->base, x, lp_build_const_scalar(bld->base.type, bld->xstep));
if (quad_index == 1 || quad_index == 3) {
/* top-right or bottom-right quad in block */
/* build x += xstep */
x = lp_build_add(&bld->base, x,
lp_build_const_scalar(bld->base.type, xstep));
}
if(bld->ystep)
y = lp_build_add(&bld->base, y, lp_build_const_scalar(bld->base.type, bld->ystep));
if (quad_index == 2) {
/* bottom-left quad in block */
/* build y += ystep */
y = lp_build_add(&bld->base, y,
lp_build_const_scalar(bld->base.type, ystep));
/* build x -= xstep */
x = lp_build_sub(&bld->base, x,
lp_build_const_scalar(bld->base.type, xstep));
}
lp_build_name(x, "pos.x");
lp_build_name(y, "pos.y");
@ -262,18 +310,20 @@ pos_update(struct lp_build_interp_soa_context *bld)
}
/**
* Initialize fragment shader input attribute info.
*/
void
lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
const struct tgsi_token *tokens,
boolean flatshade,
LLVMBuilderRef builder,
struct lp_type type,
LLVMValueRef a0_ptr,
LLVMValueRef dadx_ptr,
LLVMValueRef dady_ptr,
LLVMValueRef x0,
LLVMValueRef y0,
int xstep,
int ystep)
LLVMValueRef y0)
{
struct tgsi_parse_context parse;
struct tgsi_full_declaration *decl;
@ -309,7 +359,15 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
for( attrib = first; attrib <= last; ++attrib ) {
bld->mask[1 + attrib] = mask;
bld->mode[1 + attrib] = decl->Declaration.Interpolate;
/* XXX: have mesa set INTERP_CONSTANT in the fragment
* shader.
*/
if (decl->Semantic.Name == TGSI_SEMANTIC_COLOR &&
flatshade)
bld->mode[1 + attrib] = TGSI_INTERPOLATE_CONSTANT;
else
bld->mode[1 + attrib] = decl->Declaration.Interpolate;
}
bld->num_attribs = MAX2(bld->num_attribs, 1 + last + 1);
@ -331,21 +389,19 @@ lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
pos_init(bld, x0, y0);
attribs_init(bld);
bld->xstep = xstep;
bld->ystep = ystep;
coeffs_update(bld);
}
/**
* Advance the position and inputs with the xstep and ystep.
* Advance the position and inputs to the given quad within the block.
*/
void
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld)
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
int quad_index)
{
pos_update(bld);
assert(quad_index < 4);
attribs_update(bld);
pos_update(bld, quad_index);
attribs_update(bld, quad_index);
}

View file

@ -63,9 +63,6 @@ struct lp_build_interp_soa_context
LLVMValueRef dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
LLVMValueRef dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
int xstep;
int ystep;
/* Attribute values before perspective divide */
LLVMValueRef attribs_pre[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
@ -82,18 +79,18 @@ struct lp_build_interp_soa_context
void
lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld,
const struct tgsi_token *tokens,
boolean flatshade,
LLVMBuilderRef builder,
struct lp_type type,
LLVMValueRef a0_ptr,
LLVMValueRef dadx_ptr,
LLVMValueRef dady_ptr,
LLVMValueRef x0,
LLVMValueRef y0,
int xstep,
int ystep);
LLVMValueRef y0);
void
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld);
lp_build_interp_soa_update(struct lp_build_interp_soa_context *bld,
int quad_index);
#endif /* LP_BLD_INTERP_H */

View file

@ -42,13 +42,17 @@
#include "lp_bld_logic.h"
/**
* Build code to compare two values 'a' and 'b' of 'type' using the given func.
* \param func one of PIPE_FUNC_x
*/
LLVMValueRef
lp_build_cmp(struct lp_build_context *bld,
unsigned func,
LLVMValueRef a,
LLVMValueRef b)
lp_build_compare(LLVMBuilderRef builder,
const struct lp_type type,
unsigned func,
LLVMValueRef a,
LLVMValueRef b)
{
const struct lp_type type = bld->type;
LLVMTypeRef vec_type = lp_build_vec_type(type);
LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
LLVMValueRef zeros = LLVMConstNull(int_vec_type);
@ -57,6 +61,9 @@ lp_build_cmp(struct lp_build_context *bld,
LLVMValueRef res;
unsigned i;
assert(func >= PIPE_FUNC_NEVER);
assert(func <= PIPE_FUNC_ALWAYS);
if(func == PIPE_FUNC_NEVER)
return zeros;
if(func == PIPE_FUNC_ALWAYS)
@ -69,6 +76,7 @@ lp_build_cmp(struct lp_build_context *bld,
#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
if(type.width * type.length == 128) {
if(type.floating && util_cpu_caps.has_sse) {
/* float[4] comparison */
LLVMValueRef args[3];
unsigned cc;
boolean swap;
@ -97,7 +105,7 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
return bld->undef;
return lp_build_undef(type);
}
if(swap) {
@ -110,14 +118,15 @@ lp_build_cmp(struct lp_build_context *bld,
}
args[2] = LLVMConstInt(LLVMInt8Type(), cc, 0);
res = lp_build_intrinsic(bld->builder,
res = lp_build_intrinsic(builder,
"llvm.x86.sse.cmp.ps",
vec_type,
args, 3);
res = LLVMBuildBitCast(bld->builder, res, int_vec_type, "");
res = LLVMBuildBitCast(builder, res, int_vec_type, "");
return res;
}
else if(util_cpu_caps.has_sse2) {
/* int[4] comparison */
static const struct {
unsigned swap:1;
unsigned eq:1;
@ -153,7 +162,7 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
return bld->undef;
return lp_build_undef(type);
}
/* There are no signed byte and unsigned word/dword comparison
@ -163,8 +172,8 @@ lp_build_cmp(struct lp_build_context *bld,
((type.width == 8 && type.sign) ||
(type.width != 8 && !type.sign))) {
LLVMValueRef msb = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1));
a = LLVMBuildXor(bld->builder, a, msb, "");
b = LLVMBuildXor(bld->builder, b, msb, "");
a = LLVMBuildXor(builder, a, msb, "");
b = LLVMBuildXor(builder, b, msb, "");
}
if(table[func].swap) {
@ -177,14 +186,14 @@ lp_build_cmp(struct lp_build_context *bld,
}
if(table[func].eq)
res = lp_build_intrinsic(bld->builder, pcmpeq, vec_type, args, 2);
res = lp_build_intrinsic(builder, pcmpeq, vec_type, args, 2);
else if (table[func].gt)
res = lp_build_intrinsic(bld->builder, pcmpgt, vec_type, args, 2);
res = lp_build_intrinsic(builder, pcmpgt, vec_type, args, 2);
else
res = LLVMConstNull(vec_type);
if(table[func].not)
res = LLVMBuildNot(bld->builder, res, "");
res = LLVMBuildNot(builder, res, "");
return res;
}
@ -220,28 +229,28 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
return bld->undef;
return lp_build_undef(type);
}
#if 0
/* XXX: Although valid IR, no LLVM target currently support this */
cond = LLVMBuildFCmp(bld->builder, op, a, b, "");
res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
cond = LLVMBuildFCmp(builder, op, a, b, "");
res = LLVMBuildSelect(builder, cond, ones, zeros, "");
#else
debug_printf("%s: warning: using slow element-wise vector comparison\n",
__FUNCTION__);
res = LLVMGetUndef(int_vec_type);
for(i = 0; i < type.length; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
cond = LLVMBuildFCmp(bld->builder, op,
LLVMBuildExtractElement(bld->builder, a, index, ""),
LLVMBuildExtractElement(bld->builder, b, index, ""),
cond = LLVMBuildFCmp(builder, op,
LLVMBuildExtractElement(builder, a, index, ""),
LLVMBuildExtractElement(builder, b, index, ""),
"");
cond = LLVMBuildSelect(bld->builder, cond,
cond = LLVMBuildSelect(builder, cond,
LLVMConstExtractElement(ones, index),
LLVMConstExtractElement(zeros, index),
"");
res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
res = LLVMBuildInsertElement(builder, res, cond, index, "");
}
#endif
}
@ -268,28 +277,28 @@ lp_build_cmp(struct lp_build_context *bld,
break;
default:
assert(0);
return bld->undef;
return lp_build_undef(type);
}
#if 0
/* XXX: Although valid IR, no LLVM target currently support this */
cond = LLVMBuildICmp(bld->builder, op, a, b, "");
res = LLVMBuildSelect(bld->builder, cond, ones, zeros, "");
cond = LLVMBuildICmp(builder, op, a, b, "");
res = LLVMBuildSelect(builder, cond, ones, zeros, "");
#else
debug_printf("%s: warning: using slow element-wise vector comparison\n",
debug_printf("%s: warning: using slow element-wise int vector comparison\n",
__FUNCTION__);
res = LLVMGetUndef(int_vec_type);
for(i = 0; i < type.length; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
cond = LLVMBuildICmp(bld->builder, op,
LLVMBuildExtractElement(bld->builder, a, index, ""),
LLVMBuildExtractElement(bld->builder, b, index, ""),
cond = LLVMBuildICmp(builder, op,
LLVMBuildExtractElement(builder, a, index, ""),
LLVMBuildExtractElement(builder, b, index, ""),
"");
cond = LLVMBuildSelect(bld->builder, cond,
cond = LLVMBuildSelect(builder, cond,
LLVMConstExtractElement(ones, index),
LLVMConstExtractElement(zeros, index),
"");
res = LLVMBuildInsertElement(bld->builder, res, cond, index, "");
res = LLVMBuildInsertElement(builder, res, cond, index, "");
}
#endif
}
@ -298,6 +307,21 @@ lp_build_cmp(struct lp_build_context *bld,
}
/**
* Build code to compare two values 'a' and 'b' using the given func.
* \param func one of PIPE_FUNC_x
*/
LLVMValueRef
lp_build_cmp(struct lp_build_context *bld,
unsigned func,
LLVMValueRef a,
LLVMValueRef b)
{
return lp_build_compare(bld->builder, bld->type, func, a, b);
}
LLVMValueRef
lp_build_select(struct lp_build_context *bld,
LLVMValueRef mask,

View file

@ -46,6 +46,14 @@ struct lp_type;
struct lp_build_context;
LLVMValueRef
lp_build_compare(LLVMBuilderRef builder,
const struct lp_type type,
unsigned func,
LLVMValueRef a,
LLVMValueRef b);
/**
* @param func is one of PIPE_FUNC_xxx
*/

View file

@ -172,7 +172,7 @@ lp_build_sample_wrap(struct lp_build_sample_context *bld,
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
/* FIXME */
_debug_printf("warning: failed to translate texture wrap mode %s\n",
_debug_printf("llvmpipe: failed to translate texture wrap mode %s\n",
debug_dump_tex_wrap(wrap_mode, TRUE));
coord = lp_build_max(int_coord_bld, coord, int_coord_bld->zero);
coord = lp_build_min(int_coord_bld, coord, length_minus_one);
@ -201,9 +201,13 @@ lp_build_sample_2d_nearest_soa(struct lp_build_sample_context *bld,
x = lp_build_ifloor(&bld->coord_bld, s);
y = lp_build_ifloor(&bld->coord_bld, t);
lp_build_name(x, "tex.x.floor");
lp_build_name(y, "tex.y.floor");
x = lp_build_sample_wrap(bld, x, width, bld->static_state->pot_width, bld->static_state->wrap_s);
y = lp_build_sample_wrap(bld, y, height, bld->static_state->pot_height, bld->static_state->wrap_t);
lp_build_name(x, "tex.x.wrapped");
lp_build_name(y, "tex.y.wrapped");
lp_build_sample_texel_soa(bld, x, y, stride, data_ptr, texel);
}

View file

@ -157,6 +157,27 @@ lp_build_int_vec_type(struct lp_type type)
}
/**
* Build int32[4] vector type
*/
LLVMTypeRef
lp_build_int32_vec4_type(void)
{
struct lp_type t;
LLVMTypeRef type;
memset(&t, 0, sizeof(t));
t.floating = FALSE; /* floating point values */
t.sign = TRUE; /* values are signed */
t.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */
t.width = 32; /* 32-bit int */
t.length = 4; /* 4 elements per vector */
type = lp_build_int_elem_type(t);
return LLVMVectorType(type, t.length);
}
struct lp_type
lp_int_type(struct lp_type type)
{

View file

@ -252,6 +252,10 @@ LLVMTypeRef
lp_build_int_vec_type(struct lp_type type);
LLVMTypeRef
lp_build_int32_vec4_type();
struct lp_type
lp_int_type(struct lp_type type);

View file

@ -108,32 +108,6 @@ llvmpipe_user_buffer_create(struct pipe_screen *screen,
}
static void
llvmpipe_fence_reference(struct pipe_screen *screen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
}
static int
llvmpipe_fence_signalled(struct pipe_screen *screen,
struct pipe_fence_handle *fence,
unsigned flag)
{
return 0;
}
static int
llvmpipe_fence_finish(struct pipe_screen *screen,
struct pipe_fence_handle *fence,
unsigned flag)
{
return 0;
}
void
llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
{
@ -142,9 +116,4 @@ llvmpipe_init_screen_buffer_funcs(struct pipe_screen *screen)
screen->buffer_map = llvmpipe_buffer_map;
screen->buffer_unmap = llvmpipe_buffer_unmap;
screen->buffer_destroy = llvmpipe_buffer_destroy;
screen->fence_reference = llvmpipe_fence_reference;
screen->fence_signalled = llvmpipe_fence_signalled;
screen->fence_finish = llvmpipe_fence_finish;
}

View file

@ -33,12 +33,9 @@
#include "pipe/p_defines.h"
#include "util/u_pack_color.h"
#include "lp_clear.h"
#include "lp_context.h"
#include "lp_surface.h"
#include "lp_state.h"
#include "lp_tile_cache.h"
#include "lp_setup.h"
/**
@ -46,37 +43,16 @@
* No masking, no scissor (clear entire buffer).
*/
void
llvmpipe_clear(struct pipe_context *pipe, unsigned buffers, const float *rgba,
double depth, unsigned stencil)
llvmpipe_clear(struct pipe_context *pipe,
unsigned buffers,
const float *rgba,
double depth,
unsigned stencil)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
union util_color uc;
unsigned cv;
uint i;
if (llvmpipe->no_rast)
return;
#if 0
llvmpipe_update_derived(llvmpipe); /* not needed?? */
#endif
if (buffers & PIPE_CLEAR_COLOR) {
for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
struct pipe_surface *ps = llvmpipe->framebuffer.cbufs[i];
util_pack_color(rgba, ps->format, &uc);
lp_tile_cache_clear(llvmpipe->cbuf_cache[i], rgba, uc.ui);
}
llvmpipe->dirty_render_cache = TRUE;
}
if (buffers & PIPE_CLEAR_DEPTHSTENCIL) {
struct pipe_surface *ps = llvmpipe->framebuffer.zsbuf;
cv = util_pack_z_stencil(ps->format, depth, stencil);
/* non-cached surface */
pipe->surface_fill(pipe, ps, 0, 0, ps->width, ps->height, cv);
}
lp_setup_clear( llvmpipe->setup, rgba, depth, stencil, buffers );
}

View file

@ -39,65 +39,16 @@
#include "lp_clear.h"
#include "lp_context.h"
#include "lp_flush.h"
#include "lp_prim_vbuf.h"
#include "lp_perf.h"
#include "lp_state.h"
#include "lp_surface.h"
#include "lp_tile_cache.h"
#include "lp_tex_cache.h"
#include "lp_texture.h"
#include "lp_winsys.h"
#include "lp_query.h"
#include "lp_setup.h"
/**
* Map any drawing surfaces which aren't already mapped
*/
void
llvmpipe_map_transfers(struct llvmpipe_context *lp)
{
struct pipe_screen *screen = lp->pipe.screen;
struct pipe_surface *zsbuf = lp->framebuffer.zsbuf;
unsigned i;
for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
}
if(zsbuf) {
if(!lp->zsbuf_transfer)
lp->zsbuf_transfer = screen->get_tex_transfer(screen, zsbuf->texture,
zsbuf->face, zsbuf->level, zsbuf->zslice,
PIPE_TRANSFER_READ_WRITE,
0, 0, zsbuf->width, zsbuf->height);
if(lp->zsbuf_transfer && !lp->zsbuf_map)
lp->zsbuf_map = screen->transfer_map(screen, lp->zsbuf_transfer);
}
}
/**
* Unmap any mapped drawing surfaces
*/
void
llvmpipe_unmap_transfers(struct llvmpipe_context *lp)
{
uint i;
for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
lp_tile_cache_unmap_transfers(lp->cbuf_cache[i]);
}
if(lp->zsbuf_transfer) {
struct pipe_screen *screen = lp->pipe.screen;
if(lp->zsbuf_map) {
screen->transfer_unmap(screen, lp->zsbuf_transfer);
lp->zsbuf_map = NULL;
}
}
}
static void llvmpipe_destroy( struct pipe_context *pipe )
@ -105,22 +56,24 @@ static void llvmpipe_destroy( struct pipe_context *pipe )
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
uint i;
lp_print_counters();
/* This will also destroy llvmpipe->setup:
*/
if (llvmpipe->draw)
draw_destroy( llvmpipe->draw );
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
lp_destroy_tile_cache(llvmpipe->cbuf_cache[i]);
pipe_surface_reference(&llvmpipe->framebuffer.cbufs[i], NULL);
}
pipe_surface_reference(&llvmpipe->framebuffer.zsbuf, NULL);
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
lp_destroy_tex_tile_cache(llvmpipe->tex_cache[i]);
pipe_texture_reference(&llvmpipe->texture[i], NULL);
}
for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
lp_destroy_tex_tile_cache(llvmpipe->vertex_tex_cache[i]);
pipe_texture_reference(&llvmpipe->vertex_textures[i], NULL);
}
@ -139,33 +92,8 @@ llvmpipe_is_texture_referenced( struct pipe_context *pipe,
unsigned face, unsigned level)
{
struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
unsigned i;
/* check if any of the bound drawing surfaces are this texture */
if(llvmpipe->dirty_render_cache) {
for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
if(llvmpipe->framebuffer.cbufs[i] &&
llvmpipe->framebuffer.cbufs[i]->texture == texture)
return PIPE_REFERENCED_FOR_WRITE;
}
if(llvmpipe->framebuffer.zsbuf &&
llvmpipe->framebuffer.zsbuf->texture == texture)
return PIPE_REFERENCED_FOR_WRITE;
}
/* check if any of the tex_cache textures are this texture */
for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
if (llvmpipe->tex_cache[i] &&
llvmpipe->tex_cache[i]->texture == texture)
return PIPE_REFERENCED_FOR_READ;
}
for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) {
if (llvmpipe->vertex_tex_cache[i] &&
llvmpipe->vertex_tex_cache[i]->texture == texture)
return PIPE_REFERENCED_FOR_READ;
}
return PIPE_UNREFERENCED;
return lp_setup_is_texture_referenced(llvmpipe->setup, texture);
}
static unsigned int
@ -179,7 +107,6 @@ struct pipe_context *
llvmpipe_create( struct pipe_screen *screen )
{
struct llvmpipe_context *llvmpipe;
uint i;
llvmpipe = align_malloc(sizeof(struct llvmpipe_context), 16);
if (!llvmpipe)
@ -243,19 +170,6 @@ llvmpipe_create( struct pipe_screen *screen )
llvmpipe->pipe.is_buffer_referenced = llvmpipe_is_buffer_referenced;
llvmpipe_init_query_funcs( llvmpipe );
llvmpipe_init_texture_funcs( llvmpipe );
/*
* Alloc caches for accessing drawing surfaces and textures.
*/
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
llvmpipe->cbuf_cache[i] = lp_create_tile_cache( screen );
for (i = 0; i < PIPE_MAX_SAMPLERS; i++)
llvmpipe->tex_cache[i] = lp_create_tex_tile_cache( screen );
for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++)
llvmpipe->vertex_tex_cache[i] = lp_create_tex_tile_cache(screen);
/*
* Create drawing context and plug our rendering stage into it.
@ -269,19 +183,11 @@ llvmpipe_create( struct pipe_screen *screen )
if (debug_get_bool_option( "LP_NO_RAST", FALSE ))
llvmpipe->no_rast = TRUE;
llvmpipe->vbuf_backend = lp_create_vbuf_backend(llvmpipe);
if (!llvmpipe->vbuf_backend)
llvmpipe->setup = lp_setup_create( screen,
llvmpipe->draw );
if (!llvmpipe->setup)
goto fail;
llvmpipe->vbuf = draw_vbuf_stage(llvmpipe->draw, llvmpipe->vbuf_backend);
if (!llvmpipe->vbuf)
goto fail;
draw_set_rasterize_stage(llvmpipe->draw, llvmpipe->vbuf);
draw_set_render(llvmpipe->draw, llvmpipe->vbuf_backend);
/* plug in AA line/point stages */
draw_install_aaline_stage(llvmpipe->draw, &llvmpipe->pipe);
draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
@ -293,6 +199,8 @@ llvmpipe_create( struct pipe_screen *screen )
lp_init_surface_functions(llvmpipe);
lp_reset_counters();
return &llvmpipe->pipe;
fail:

View file

@ -42,12 +42,10 @@
struct llvmpipe_vbuf_render;
struct draw_context;
struct draw_stage;
struct llvmpipe_tile_cache;
struct llvmpipe_tex_tile_cache;
struct lp_fragment_shader;
struct lp_vertex_shader;
struct lp_blend_state;
struct setup_context;
struct llvmpipe_context {
struct pipe_context pipe; /**< base class */
@ -62,7 +60,7 @@ struct llvmpipe_context {
const struct lp_vertex_shader *vs;
/** Other rendering state */
struct pipe_blend_color blend_color[4][16];
struct pipe_blend_color blend_color;
struct pipe_clip_state clip;
struct pipe_buffer *constants[PIPE_SHADER_TYPES];
struct pipe_framebuffer_state framebuffer;
@ -94,49 +92,19 @@ struct llvmpipe_context {
/** Vertex format */
struct vertex_info vertex_info;
struct vertex_info vertex_info_vbuf;
/** Which vertex shader output slot contains point size */
int psize_slot;
/* The reduced version of the primitive supplied by the state
* tracker.
*/
unsigned reduced_api_prim;
/* The reduced primitive after unfilled triangles, wide-line
* decomposition, etc, are taken into account. This is the
* primitive actually rasterized.
*/
unsigned reduced_prim;
/** Derived from scissor and surface bounds: */
struct pipe_scissor_state cliprect;
unsigned line_stipple_counter;
/** The tiling engine */
struct setup_context *setup;
/** The primitive drawing context */
struct draw_context *draw;
/** Draw module backend */
struct vbuf_render *vbuf_backend;
struct draw_stage *vbuf;
boolean dirty_render_cache;
struct llvmpipe_tile_cache *cbuf_cache[PIPE_MAX_COLOR_BUFS];
/* TODO: we shouldn't be using external interfaces internally like this */
struct pipe_transfer *zsbuf_transfer;
uint8_t *zsbuf_map;
unsigned tex_timestamp;
struct llvmpipe_tex_tile_cache *tex_cache[PIPE_MAX_SAMPLERS];
struct llvmpipe_tex_tile_cache *vertex_tex_cache[PIPE_MAX_VERTEX_SAMPLERS];
boolean no_rast;
unsigned no_rast : 1;
struct lp_jit_context jit_context;
};

View file

@ -45,6 +45,11 @@ st_print_current(void);
#define DEBUG_QUERY 0x40
#define DEBUG_SCREEN 0x80
#define DEBUG_JIT 0x100
#define DEBUG_SHOW_TILES 0x200
#define DEBUG_SHOW_SUBTILES 0x400
#define DEBUG_COUNTERS 0x800
#define DEBUG_NO_LLVM_OPT 0x1000
#ifdef DEBUG
extern int LP_DEBUG;

View file

@ -68,13 +68,9 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
struct draw_context *draw = lp->draw;
unsigned i;
lp->reduced_api_prim = u_reduced_prim(mode);
if (lp->dirty)
llvmpipe_update_derived( lp );
llvmpipe_map_transfers(lp);
/*
* Map vertex buffers
*/
@ -116,10 +112,6 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
* internally when this condition is seen?)
*/
draw_flush(draw);
/* Note: leave drawing surfaces mapped */
lp->dirty_render_cache = TRUE;
}

View file

@ -0,0 +1,110 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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 "pipe/p_screen.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "lp_fence.h"
struct lp_fence *
lp_fence_create(unsigned rank)
{
struct lp_fence *fence = CALLOC_STRUCT(lp_fence);
pipe_reference_init(&fence->reference, 1);
pipe_mutex_init(fence->mutex);
pipe_condvar_init(fence->signalled);
fence->rank = rank;
return fence;
}
static void
lp_fence_destroy(struct lp_fence *fence)
{
pipe_mutex_destroy(fence->mutex);
pipe_condvar_destroy(fence->signalled);
FREE(fence);
}
static void
llvmpipe_fence_reference(struct pipe_screen *screen,
struct pipe_fence_handle **ptr,
struct pipe_fence_handle *fence)
{
struct lp_fence *old = (struct lp_fence *) *ptr;
struct lp_fence *f = (struct lp_fence *) fence;
if (pipe_reference(&old->reference, &f->reference)) {
lp_fence_destroy(old);
}
}
static int
llvmpipe_fence_signalled(struct pipe_screen *screen,
struct pipe_fence_handle *fence,
unsigned flag)
{
struct lp_fence *f = (struct lp_fence *) fence;
return f->count == f->rank;
}
static int
llvmpipe_fence_finish(struct pipe_screen *screen,
struct pipe_fence_handle *fence_handle,
unsigned flag)
{
struct lp_fence *fence = (struct lp_fence *) fence_handle;
pipe_mutex_lock(fence->mutex);
while (fence->count < fence->rank) {
pipe_condvar_wait(fence->signalled, fence->mutex);
}
pipe_mutex_unlock(fence->mutex);
return 0;
}
void
llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen)
{
screen->fence_reference = llvmpipe_fence_reference;
screen->fence_signalled = llvmpipe_fence_signalled;
screen->fence_finish = llvmpipe_fence_finish;
}

View file

@ -0,0 +1,60 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#ifndef LP_FENCE_H
#define LP_FENCE_H
#include "os/os_thread.h"
#include "pipe/p_state.h"
struct pipe_screen;
struct lp_fence
{
struct pipe_reference reference;
pipe_mutex mutex;
pipe_condvar signalled;
unsigned rank;
unsigned count;
};
struct lp_fence *
lp_fence_create(unsigned rank);
void
llvmpipe_init_screen_fence_funcs(struct pipe_screen *screen);
#endif /* LP_FENCE_H */

View file

@ -35,8 +35,7 @@
#include "lp_flush.h"
#include "lp_context.h"
#include "lp_surface.h"
#include "lp_state.h"
#include "lp_tile_cache.h"
#include "lp_setup.h"
void
@ -45,56 +44,52 @@ llvmpipe_flush( struct pipe_context *pipe,
struct pipe_fence_handle **fence )
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
uint i;
draw_flush(llvmpipe->draw);
if (flags & PIPE_FLUSH_SWAPBUFFERS) {
/* If this is a swapbuffers, just flush color buffers.
*
* The zbuffer changes are not discarded, but held in the cache
* in the hope that a later clear will wipe them out.
*/
for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
if (llvmpipe->cbuf_cache[i]) {
lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
}
if (fence) {
if ((flags & (PIPE_FLUSH_SWAPBUFFERS |
PIPE_FLUSH_RENDER_CACHE))) {
/* if we're going to flush the setup/rasterization modules, emit
* a fence.
* XXX this (and the code below) may need fine tuning...
*/
*fence = lp_setup_fence( llvmpipe->setup );
}
else {
*fence = NULL;
}
}
/* Need this call for hardware buffers before swapbuffers.
*
* there should probably be another/different flush-type function
* that's called before swapbuffers because we don't always want
* to unmap surfaces when flushing.
*/
llvmpipe_unmap_transfers(llvmpipe);
/* XXX the lp_setup_flush(flags) param is not a bool, and it's ignored
* at this time!
*/
if (flags & PIPE_FLUSH_SWAPBUFFERS) {
lp_setup_flush( llvmpipe->setup, FALSE );
}
else if (flags & PIPE_FLUSH_RENDER_CACHE) {
for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++)
if (llvmpipe->cbuf_cache[i]) {
lp_tile_cache_map_transfers(llvmpipe->cbuf_cache[i]);
lp_flush_tile_cache(llvmpipe->cbuf_cache[i]);
}
/* FIXME: untile zsbuf! */
llvmpipe->dirty_render_cache = FALSE;
lp_setup_flush( llvmpipe->setup, TRUE );
}
/* Enable to dump BMPs of the color/depth buffers each frame */
#if 0
if(flags & PIPE_FLUSH_FRAME) {
if (flags & PIPE_FLUSH_FRAME) {
static unsigned frame_no = 1;
static char filename[256];
util_snprintf(filename, sizeof(filename), "cbuf_%u.bmp", frame_no);
debug_dump_surface_bmp(filename, llvmpipe->framebuffer.cbufs[0]);
util_snprintf(filename, sizeof(filename), "zsbuf_%u.bmp", frame_no);
debug_dump_surface_bmp(filename, llvmpipe->framebuffer.zsbuf);
char filename[256];
unsigned i;
for (i = 0; i < llvmpipe->framebuffer.nr_cbufs; i++) {
util_snprintf(filename, sizeof(filename), "cbuf%u_%u", i, frame_no);
debug_dump_surface(filename, llvmpipe->framebuffer.cbufs[i]);
}
if (0) {
util_snprintf(filename, sizeof(filename), "zsbuf_%u", frame_no);
debug_dump_surface(filename, llvmpipe->framebuffer.zsbuf);
}
++frame_no;
}
#endif
if (fence)
*fence = NULL;
}

View file

@ -37,6 +37,7 @@
#include "util/u_memory.h"
#include "util/u_cpu_detect.h"
#include "lp_debug.h"
#include "lp_screen.h"
#include "lp_bld_intr.h"
#include "lp_jit.h"
@ -78,13 +79,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
/* struct lp_jit_context */
{
LLVMTypeRef elem_types[4];
LLVMTypeRef elem_types[8];
LLVMTypeRef context_type;
elem_types[0] = LLVMPointerType(LLVMFloatType(), 0); /* constants */
elem_types[1] = LLVMFloatType(); /* alpha_ref_value */
elem_types[2] = LLVMPointerType(LLVMInt8Type(), 0); /* blend_color */
elem_types[3] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
elem_types[1] = LLVMFloatType(); /* alpha_ref_value */ elem_types[2] = LLVMFloatType(); /* scissor_xmin */
elem_types[3] = LLVMFloatType(); /* scissor_ymin */
elem_types[4] = LLVMFloatType(); /* scissor_xmax */
elem_types[5] = LLVMFloatType(); /* scissor_ymax */
elem_types[6] = LLVMPointerType(LLVMInt8Type(), 0); /* blend_color */
elem_types[7] = LLVMArrayType(texture_type, PIPE_MAX_SAMPLERS); /* textures */
context_type = LLVMStructType(elem_types, Elements(elem_types), 0);
@ -92,8 +96,16 @@ lp_jit_init_globals(struct llvmpipe_screen *screen)
screen->target, context_type, 0);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, alpha_ref_value,
screen->target, context_type, 1);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmin,
screen->target, context_type, 2);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymin,
screen->target, context_type, 3);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_xmax,
screen->target, context_type, 4);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, scissor_ymax,
screen->target, context_type, 5);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, blend_color,
screen->target, context_type, 6);
LP_CHECK_MEMBER_OFFSET(struct lp_jit_context, textures,
screen->target, context_type,
LP_JIT_CONTEXT_TEXTURES_INDEX);
@ -153,20 +165,23 @@ lp_jit_screen_init(struct llvmpipe_screen *screen)
screen->pass = LLVMCreateFunctionPassManager(screen->provider);
LLVMAddTargetData(screen->target, screen->pass);
/* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
* but there are more on SVN. */
/* TODO: Add more passes */
LLVMAddConstantPropagationPass(screen->pass);
if(util_cpu_caps.has_sse4_1) {
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
* and sitofp (necessary for trunc/floor/ceil/round implementation)
* somehow becomes invalid code.
*/
LLVMAddInstructionCombiningPass(screen->pass);
if ((LP_DEBUG & DEBUG_NO_LLVM_OPT) == 0) {
/* These are the passes currently listed in llvm-c/Transforms/Scalar.h,
* but there are more on SVN. */
/* TODO: Add more passes */
LLVMAddConstantPropagationPass(screen->pass);
if(util_cpu_caps.has_sse4_1) {
/* FIXME: There is a bug in this pass, whereby the combination of fptosi
* and sitofp (necessary for trunc/floor/ceil/round implementation)
* somehow becomes invalid code.
*/
LLVMAddInstructionCombiningPass(screen->pass);
}
LLVMAddPromoteMemoryToRegisterPass(screen->pass);
LLVMAddGVNPass(screen->pass);
LLVMAddCFGSimplificationPass(screen->pass);
}
LLVMAddPromoteMemoryToRegisterPass(screen->pass);
LLVMAddGVNPass(screen->pass);
LLVMAddCFGSimplificationPass(screen->pass);
lp_jit_init_globals(screen);
}

View file

@ -79,6 +79,9 @@ struct lp_jit_context
float alpha_ref_value;
/** floats, not ints */
float scissor_xmin, scissor_ymin, scissor_xmax, scissor_ymax;
/* FIXME: store (also?) in floats */
uint8_t *blend_color;
@ -92,25 +95,43 @@ struct lp_jit_context
#define lp_jit_context_alpha_ref_value(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 1, "alpha_ref_value")
#define lp_jit_context_blend_color(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 2, "blend_color")
#define lp_jit_context_scissor_xmin_value(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 2, "scissor_xmin")
#define LP_JIT_CONTEXT_TEXTURES_INDEX 3
#define lp_jit_context_scissor_ymin_value(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 3, "scissor_ymin")
#define lp_jit_context_scissor_xmax_value(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 4, "scissor_xmax")
#define lp_jit_context_scissor_ymax_value(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 5, "scissor_ymax")
#define lp_jit_context_blend_color(_builder, _ptr) \
lp_build_struct_get(_builder, _ptr, 6, "blend_color")
#define LP_JIT_CONTEXT_TEXTURES_INDEX 7
#define lp_jit_context_textures(_builder, _ptr) \
lp_build_struct_get_ptr(_builder, _ptr, LP_JIT_CONTEXT_TEXTURES_INDEX, "textures")
typedef void
(*lp_jit_frag_func)(struct lp_jit_context *context,
(*lp_jit_frag_func)(const struct lp_jit_context *context,
uint32_t x,
uint32_t y,
const void *a0,
const void *dadx,
const void *dady,
uint32_t *mask,
void *color,
void *depth);
uint8_t **color,
void *depth,
const int32_t c1,
const int32_t c2,
const int32_t c3,
const int32_t *step1,
const int32_t *step2,
const int32_t *step3);
void
lp_jit_screen_cleanup(struct llvmpipe_screen *screen);

View file

@ -0,0 +1,90 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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_debug.h"
#include "lp_debug.h"
#include "lp_perf.h"
struct lp_counters lp_count;
void
lp_reset_counters(void)
{
memset(&lp_count, 0, sizeof(lp_count));
}
void
lp_print_counters(void)
{
if (LP_DEBUG & DEBUG_COUNTERS) {
unsigned total_64, total_16, total_4;
float p1, p2, p3;
debug_printf("llvmpipe: nr_triangles: %9u\n", lp_count.nr_tris);
debug_printf("llvmpipe: nr_culled_triangles: %9u\n", lp_count.nr_culled_tris);
total_64 = (lp_count.nr_empty_64 +
lp_count.nr_fully_covered_64 +
lp_count.nr_partially_covered_64);
p1 = 100.0 * (float) lp_count.nr_empty_64 / (float) total_64;
p2 = 100.0 * (float) lp_count.nr_fully_covered_64 / (float) total_64;
p3 = 100.0 * (float) lp_count.nr_partially_covered_64 / (float) total_64;
debug_printf("llvmpipe: nr_empty_64x64: %9u (%2.0f%% of %u)\n", lp_count.nr_empty_64, p1, total_64);
debug_printf("llvmpipe: nr_fully_covered_64x64: %9u (%2.0f%% of %u)\n", lp_count.nr_fully_covered_64, p2, total_64);
debug_printf("llvmpipe: nr_partially_covered_64x64: %9u (%2.0f%% of %u)\n", lp_count.nr_partially_covered_64, p3, total_64);
total_16 = (lp_count.nr_empty_16 +
lp_count.nr_fully_covered_16 +
lp_count.nr_partially_covered_16);
p1 = 100.0 * (float) lp_count.nr_empty_16 / (float) total_16;
p2 = 100.0 * (float) lp_count.nr_fully_covered_16 / (float) total_16;
p3 = 100.0 * (float) lp_count.nr_partially_covered_16 / (float) total_16;
debug_printf("llvmpipe: nr_empty_16x16: %9u (%2.0f%% of %u)\n", lp_count.nr_empty_16, p1, total_16);
debug_printf("llvmpipe: nr_fully_covered_16x16: %9u (%2.0f%% of %u)\n", lp_count.nr_fully_covered_16, p2, total_16);
debug_printf("llvmpipe: nr_partially_covered_16x16: %9u (%2.0f%% of %u)\n", lp_count.nr_partially_covered_16, p3, total_16);
total_4 = (lp_count.nr_empty_4 + lp_count.nr_non_empty_4);
p1 = 100.0 * (float) lp_count.nr_empty_4 / (float) total_4;
p2 = 100.0 * (float) lp_count.nr_non_empty_4 / (float) total_4;
debug_printf("llvmpipe: nr_empty_4x4: %9u (%2.0f%% of %u)\n", lp_count.nr_empty_4, p1, total_4);
debug_printf("llvmpipe: nr_non_empty_4x4: %9u (%2.0f%% of %u)\n", lp_count.nr_non_empty_4, p2, total_4);
debug_printf("llvmpipe: nr_llvm_compiles: %u\n", lp_count.nr_llvm_compiles);
debug_printf("llvmpipe: total LLVM compile time: %.2f sec\n", lp_count.llvm_compile_time / 1000000.0);
debug_printf("llvmpipe: average LLVM compile time: %.2f sec\n", lp_count.llvm_compile_time / 1000000.0 / lp_count.nr_llvm_compiles);
}
}

View file

@ -0,0 +1,78 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Performance / statistic counters, etc.
*/
#ifndef LP_PERF_H
#define LP_PERF_H
/**
* Various counters
*/
struct lp_counters
{
unsigned nr_tris;
unsigned nr_culled_tris;
unsigned nr_empty_64;
unsigned nr_fully_covered_64;
unsigned nr_partially_covered_64;
unsigned nr_empty_16;
unsigned nr_fully_covered_16;
unsigned nr_partially_covered_16;
unsigned nr_empty_4;
unsigned nr_non_empty_4;
unsigned nr_llvm_compiles;
int64_t llvm_compile_time; /**< total, in microseconds */
};
extern struct lp_counters lp_count;
/** Increment the named counter (only for debug builds) */
#ifdef DEBUG
#define LP_COUNT(counter) lp_count.counter++
#define LP_COUNT_ADD(counter, incr) lp_count.counter += (incr)
#else
#define LP_COUNT(counter)
#define LP_COUNT_ADD(counter, incr) (void) incr
#endif
extern void
lp_reset_counters(void);
extern void
lp_print_counters(void);
#endif /* LP_PERF_H */

View file

@ -1,563 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Interface between 'draw' module's output and the llvmpipe rasterizer/setup
* code. When the 'draw' module has finished filling a vertex buffer, the
* draw_arrays() functions below will be called. Loop over the vertices and
* call the point/line/tri setup functions.
*
* Authors
* Brian Paul
*/
#include "lp_context.h"
#include "lp_setup.h"
#include "lp_state.h"
#include "lp_prim_vbuf.h"
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#define LP_MAX_VBUF_INDEXES 1024
#define LP_MAX_VBUF_SIZE 4096
typedef const float (*cptrf4)[4];
/**
* Subclass of vbuf_render.
*/
struct llvmpipe_vbuf_render
{
struct vbuf_render base;
struct llvmpipe_context *llvmpipe;
struct setup_context *setup;
uint prim;
uint vertex_size;
uint nr_vertices;
uint vertex_buffer_size;
void *vertex_buffer;
};
/** cast wrapper */
static struct llvmpipe_vbuf_render *
llvmpipe_vbuf_render(struct vbuf_render *vbr)
{
return (struct llvmpipe_vbuf_render *) vbr;
}
static const struct vertex_info *
lp_vbuf_get_vertex_info(struct vbuf_render *vbr)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
return llvmpipe_get_vbuf_vertex_info(cvbr->llvmpipe);
}
static boolean
lp_vbuf_allocate_vertices(struct vbuf_render *vbr,
ushort vertex_size, ushort nr_vertices)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
unsigned size = vertex_size * nr_vertices;
if (cvbr->vertex_buffer_size < size) {
align_free(cvbr->vertex_buffer);
cvbr->vertex_buffer = align_malloc(size, 16);
cvbr->vertex_buffer_size = size;
}
cvbr->vertex_size = vertex_size;
cvbr->nr_vertices = nr_vertices;
return cvbr->vertex_buffer != NULL;
}
static void
lp_vbuf_release_vertices(struct vbuf_render *vbr)
{
/* keep the old allocation for next time */
}
static void *
lp_vbuf_map_vertices(struct vbuf_render *vbr)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
return cvbr->vertex_buffer;
}
static void
lp_vbuf_unmap_vertices(struct vbuf_render *vbr,
ushort min_index,
ushort max_index )
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size );
(void) cvbr;
/* do nothing */
}
static boolean
lp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
struct setup_context *setup_ctx = cvbr->setup;
llvmpipe_setup_prepare( setup_ctx );
cvbr->llvmpipe->reduced_prim = u_reduced_prim(prim);
cvbr->prim = prim;
return TRUE;
}
static INLINE cptrf4 get_vert( const void *vertex_buffer,
int index,
int stride )
{
return (cptrf4)((char *)vertex_buffer + index * stride);
}
/**
* draw elements / indexed primitives
*/
static void
lp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
const void *vertex_buffer = cvbr->vertex_buffer;
struct setup_context *setup_ctx = cvbr->setup;
unsigned i;
switch (cvbr->prim) {
case PIPE_PRIM_POINTS:
for (i = 0; i < nr; i++) {
llvmpipe_setup_point( setup_ctx,
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINES:
for (i = 1; i < nr; i += 2) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINE_STRIP:
for (i = 1; i < nr; i ++) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINE_LOOP:
for (i = 1; i < nr; i ++) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
if (nr) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, indices[nr-1], stride),
get_vert(vertex_buffer, indices[0], stride) );
}
break;
case PIPE_PRIM_TRIANGLES:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i += 3) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-2], stride) );
}
}
else {
for (i = 2; i < nr; i += 3) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_STRIP:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
get_vert(vertex_buffer, indices[i-(i&1)], stride),
get_vert(vertex_buffer, indices[i-2], stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_FAN:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[0], stride),
get_vert(vertex_buffer, indices[i-1], stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_QUADS:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 3; i < nr; i += 4) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
}
}
else {
for (i = 3; i < nr; i += 4) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_QUAD_STRIP:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 3; i < nr; i += 2) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride));
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
}
}
else {
for (i = 3; i < nr; i += 2) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_POLYGON:
/* Almost same as tri fan but the _first_ vertex specifies the flat
* shading color. Note that the first polygon vertex is passed as
* the last triangle vertex here.
* flatshade_first state makes no difference.
*/
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[0], stride) );
}
break;
default:
assert(0);
}
}
/**
* This function is hit when the draw module is working in pass-through mode.
* It's up to us to convert the vertex array into point/line/tri prims.
*/
static void
lp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
struct llvmpipe_context *llvmpipe = cvbr->llvmpipe;
struct setup_context *setup_ctx = cvbr->setup;
const unsigned stride = llvmpipe->vertex_info_vbuf.size * sizeof(float);
const void *vertex_buffer =
(void *) get_vert(cvbr->vertex_buffer, start, stride);
unsigned i;
switch (cvbr->prim) {
case PIPE_PRIM_POINTS:
for (i = 0; i < nr; i++) {
llvmpipe_setup_point( setup_ctx,
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINES:
for (i = 1; i < nr; i += 2) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINE_STRIP:
for (i = 1; i < nr; i ++) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINE_LOOP:
for (i = 1; i < nr; i ++) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
if (nr) {
llvmpipe_setup_line( setup_ctx,
get_vert(vertex_buffer, nr-1, stride),
get_vert(vertex_buffer, 0, stride) );
}
break;
case PIPE_PRIM_TRIANGLES:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i += 3) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-2, stride) );
}
}
else {
for (i = 2; i < nr; i += 3) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_STRIP:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i++) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i+(i&1)-1, stride),
get_vert(vertex_buffer, i-(i&1), stride),
get_vert(vertex_buffer, i-2, stride) );
}
}
else {
for (i = 2; i < nr; i++) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i+(i&1)-2, stride),
get_vert(vertex_buffer, i-(i&1)-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_FAN:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, 0, stride),
get_vert(vertex_buffer, i-1, stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, 0, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_QUADS:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 3; i < nr; i += 4) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-3, stride) );
}
}
else {
for (i = 3; i < nr; i += 4) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_QUAD_STRIP:
if (llvmpipe->rasterizer->flatshade_first) {
for (i = 3; i < nr; i += 2) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-3, stride) );
}
}
else {
for (i = 3; i < nr; i += 2) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride) );
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_POLYGON:
/* Almost same as tri fan but the _first_ vertex specifies the flat
* shading color. Note that the first polygon vertex is passed as
* the last triangle vertex here.
* flatshade_first state makes no difference.
*/
for (i = 2; i < nr; i += 1) {
llvmpipe_setup_tri( setup_ctx,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, 0, stride) );
}
break;
default:
assert(0);
}
}
static void
lp_vbuf_destroy(struct vbuf_render *vbr)
{
struct llvmpipe_vbuf_render *cvbr = llvmpipe_vbuf_render(vbr);
llvmpipe_setup_destroy_context(cvbr->setup);
FREE(cvbr);
}
/**
* Create the post-transform vertex handler for the given context.
*/
struct vbuf_render *
lp_create_vbuf_backend(struct llvmpipe_context *lp)
{
struct llvmpipe_vbuf_render *cvbr = CALLOC_STRUCT(llvmpipe_vbuf_render);
assert(lp->draw);
cvbr->base.max_indices = LP_MAX_VBUF_INDEXES;
cvbr->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
cvbr->base.get_vertex_info = lp_vbuf_get_vertex_info;
cvbr->base.allocate_vertices = lp_vbuf_allocate_vertices;
cvbr->base.map_vertices = lp_vbuf_map_vertices;
cvbr->base.unmap_vertices = lp_vbuf_unmap_vertices;
cvbr->base.set_primitive = lp_vbuf_set_primitive;
cvbr->base.draw = lp_vbuf_draw;
cvbr->base.draw_arrays = lp_vbuf_draw_arrays;
cvbr->base.release_vertices = lp_vbuf_release_vertices;
cvbr->base.destroy = lp_vbuf_destroy;
cvbr->llvmpipe = lp;
cvbr->setup = llvmpipe_setup_create_context(cvbr->llvmpipe);
return &cvbr->base;
}

View file

@ -1,115 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
#ifndef LP_QUAD_H
#define LP_QUAD_H
#include "pipe/p_compiler.h"
#include "pipe/p_state.h"
#include "tgsi/tgsi_exec.h"
#define QUAD_PRIM_POINT 1
#define QUAD_PRIM_LINE 2
#define QUAD_PRIM_TRI 3
/* The rasterizer generates 2x2 quads of fragment and feeds them to
* the current fp_machine (see below).
* Remember that Y=0=top with Y increasing down the window.
*/
#define QUAD_TOP_LEFT 0
#define QUAD_TOP_RIGHT 1
#define QUAD_BOTTOM_LEFT 2
#define QUAD_BOTTOM_RIGHT 3
#define MASK_TOP_LEFT (1 << QUAD_TOP_LEFT)
#define MASK_TOP_RIGHT (1 << QUAD_TOP_RIGHT)
#define MASK_BOTTOM_LEFT (1 << QUAD_BOTTOM_LEFT)
#define MASK_BOTTOM_RIGHT (1 << QUAD_BOTTOM_RIGHT)
#define MASK_ALL 0xf
/**
* Quad stage inputs (pos, coverage, front/back face, etc)
*/
struct quad_header_input
{
int x0, y0; /**< quad window pos, always even */
float coverage[QUAD_SIZE]; /**< fragment coverage for antialiasing */
unsigned facing:1; /**< Front (0) or back (1) facing? */
unsigned prim:2; /**< QUAD_PRIM_POINT, LINE, TRI */
};
/**
* Quad stage inputs/outputs.
*/
struct quad_header_inout
{
unsigned mask:4;
};
/**
* Quad stage outputs (color & depth).
*/
struct quad_header_output
{
/** colors in SOA format (rrrr, gggg, bbbb, aaaa) */
PIPE_ALIGN_VAR(16) float color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][QUAD_SIZE];
};
/**
* Input interpolation coefficients
*/
struct quad_interp_coef
{
PIPE_ALIGN_VAR(16) float a0[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
PIPE_ALIGN_VAR(16) float dadx[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
PIPE_ALIGN_VAR(16) float dady[1 + PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
};
/**
* Encodes everything we need to know about a 2x2 pixel block. Uses
* "Channel-Serial" or "SoA" layout.
*/
struct quad_header {
struct quad_header_input input;
struct quad_header_inout inout;
/* Redundant/duplicated:
*/
const struct quad_interp_coef *coef;
};
#endif /* LP_QUAD_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* The rast code is concerned with rasterization of command bins.
* Each screen tile has a bin associated with it. To render the
* scene we iterate over the tile bins and execute the commands
* in each bin.
* We'll do that with multiple threads...
*/
#ifndef LP_RAST_H
#define LP_RAST_H
#include "pipe/p_compiler.h"
#include "lp_jit.h"
struct lp_rasterizer;
struct lp_scene;
struct lp_scene_queue;
struct lp_fence;
struct cmd_bin;
struct pipe_screen;
/** For sub-pixel positioning */
#define FIXED_ORDER 4
#define FIXED_ONE (1<<FIXED_ORDER)
/**
* Rasterization state.
* Objects of this type are put into the shared data bin and pointed
* to by commands in the per-tile bins.
*/
struct lp_rast_state {
/* State for the shader. This also contains state which feeds into
* the fragment shader, such as blend color and alpha ref value.
*/
struct lp_jit_context jit_context;
/* The shader itself. Probably we also need to pass a pointer to
* the tile color/z/stencil data somehow:
* jit_function[0] skips the triangle in/out test code
* jit_function[1] does triangle in/out testing
*/
lp_jit_frag_func jit_function[2];
boolean opaque;
};
/**
* Coefficients necessary to run the shader at a given location.
* First coefficient is position.
* These pointers point into the bin data buffer.
*/
struct lp_rast_shader_inputs {
float (*a0)[4];
float (*dadx)[4];
float (*dady)[4];
/* edge/step info for 3 edges and 4x4 block of pixels */
PIPE_ALIGN_VAR(16) int step[3][16];
};
/**
* Rasterization information for a triangle known to be in this bin,
* plus inputs to run the shader:
* These fields are tile- and bin-independent.
* Objects of this type are put into the setup_context::data buffer.
*/
struct lp_rast_triangle {
/* one-pixel sized trivial accept offsets for each plane */
int ei1;
int ei2;
int ei3;
/* one-pixel sized trivial reject offsets for each plane */
int eo1;
int eo2;
int eo3;
/* y deltas for vertex pairs (in fixed pt) */
int dy12;
int dy23;
int dy31;
/* x deltas for vertex pairs (in fixed pt) */
int dx12;
int dx23;
int dx31;
/* edge function values at minx,miny ?? */
int c1, c2, c3;
/* inputs for the shader */
PIPE_ALIGN_VAR(16) struct lp_rast_shader_inputs inputs;
};
struct lp_rasterizer *lp_rast_create( struct pipe_screen *screen,
struct lp_scene_queue *empty );
void lp_rast_destroy( struct lp_rasterizer * );
unsigned lp_rast_get_num_threads( struct lp_rasterizer * );
void lp_rasterize_scene( struct lp_rasterizer *rast,
struct lp_scene *scene,
const struct pipe_framebuffer_state *fb,
bool write_depth );
union lp_rast_cmd_arg {
const struct lp_rast_shader_inputs *shade_tile;
const struct lp_rast_triangle *triangle;
const struct lp_rast_state *set_state;
uint8_t clear_color[4];
unsigned clear_zstencil;
struct lp_fence *fence;
};
/* Cast wrappers. Hopefully these compile to noops!
*/
static INLINE const union lp_rast_cmd_arg
lp_rast_arg_inputs( const struct lp_rast_shader_inputs *shade_tile )
{
union lp_rast_cmd_arg arg;
arg.shade_tile = shade_tile;
return arg;
}
static INLINE const union lp_rast_cmd_arg
lp_rast_arg_triangle( const struct lp_rast_triangle *triangle )
{
union lp_rast_cmd_arg arg;
arg.triangle = triangle;
return arg;
}
static INLINE const union lp_rast_cmd_arg
lp_rast_arg_state( const struct lp_rast_state *state )
{
union lp_rast_cmd_arg arg;
arg.set_state = state;
return arg;
}
static INLINE const union lp_rast_cmd_arg
lp_rast_arg_fence( struct lp_fence *fence )
{
union lp_rast_cmd_arg arg;
arg.fence = fence;
return arg;
}
static INLINE const union lp_rast_cmd_arg
lp_rast_arg_null( void )
{
union lp_rast_cmd_arg arg;
arg.set_state = NULL;
return arg;
}
/**
* Binnable Commands.
* These get put into bins by the setup code and are called when
* the bins are executed.
*/
void lp_rast_clear_color( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_clear_zstencil( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_load_color( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_load_zstencil( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_set_state( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_triangle( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_shade_tile( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
void lp_rast_fence( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
#endif

View file

@ -0,0 +1,172 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#ifndef LP_RAST_PRIV_H
#define LP_RAST_PRIV_H
#include "os/os_thread.h"
#include "lp_rast.h"
#include "lp_tile_soa.h"
#define MAX_THREADS 8 /* XXX probably temporary here */
struct pipe_transfer;
struct pipe_screen;
struct lp_rasterizer;
/**
* A tile's color and depth memory.
* We can choose whatever layout for the internal tile storage we prefer.
*/
struct lp_rast_tile
{
uint8_t *color[PIPE_MAX_COLOR_BUFS];
uint32_t *depth;
};
/**
* Per-thread rasterization state
*/
struct lp_rasterizer_task
{
struct lp_rast_tile tile; /** Tile color/z/stencil memory */
unsigned x, y; /**< Pos of this tile in framebuffer, in pixels */
const struct lp_rast_state *current_state;
/** "back" pointer */
struct lp_rasterizer *rast;
/** "my" index */
unsigned thread_index;
pipe_semaphore work_ready;
pipe_semaphore work_done;
};
/**
* This is the state required while rasterizing tiles.
* Note that this contains per-thread information too.
* The tile size is TILE_SIZE x TILE_SIZE pixels.
*/
struct lp_rasterizer
{
boolean clipped_tile;
boolean check_for_clipped_tiles;
/* Framebuffer stuff
*/
struct pipe_screen *screen;
struct pipe_transfer *cbuf_transfer[PIPE_MAX_COLOR_BUFS];
struct pipe_transfer *zsbuf_transfer;
void *cbuf_map[PIPE_MAX_COLOR_BUFS];
void *zsbuf_map;
struct {
struct pipe_framebuffer_state fb;
boolean write_color;
boolean write_zstencil;
unsigned clear_color;
unsigned clear_depth;
char clear_stencil;
} state;
/** The incoming queue of scenes ready to rasterize */
struct lp_scene_queue *full_scenes;
/** The outgoing queue of processed scenes to return to setup modulee */
struct lp_scene_queue *empty_scenes;
/** The scene currently being rasterized by the threads */
struct lp_scene *curr_scene;
/** A task object for each rasterization thread */
struct lp_rasterizer_task tasks[MAX_THREADS];
unsigned num_threads;
pipe_thread threads[MAX_THREADS];
/** For synchronizing the rasterization threads */
pipe_barrier barrier;
};
void lp_rast_shade_quads( struct lp_rasterizer *rast,
unsigned thread_index,
const struct lp_rast_shader_inputs *inputs,
unsigned x, unsigned y,
int32_t c1, int32_t c2, int32_t c3);
/**
* Shade all pixels in a 4x4 block. The fragment code omits the
* triangle in/out tests.
* \param x, y location of 4x4 block in window coords
*/
static INLINE void
lp_rast_shade_quads_all( struct lp_rasterizer *rast,
unsigned thread_index,
const struct lp_rast_shader_inputs *inputs,
unsigned x, unsigned y )
{
const struct lp_rast_state *state = rast->tasks[thread_index].current_state;
struct lp_rast_tile *tile = &rast->tasks[thread_index].tile;
const unsigned ix = x % TILE_SIZE, iy = y % TILE_SIZE;
uint8_t *color[PIPE_MAX_COLOR_BUFS];
void *depth;
unsigned block_offset, i;
/* offset of the containing 16x16 pixel block within the tile */
block_offset = (iy / 4) * (16 * 16) + (ix / 4) * 16;
/* color buffer */
for (i = 0; i < rast->state.fb.nr_cbufs; i++)
color[i] = tile->color[i] + 4 * block_offset;
/* depth buffer */
depth = tile->depth + block_offset;
/* run shader */
state->jit_function[0]( &state->jit_context,
x, y,
inputs->a0,
inputs->dadx,
inputs->dady,
color,
depth,
INT_MIN, INT_MIN, INT_MIN,
NULL, NULL, NULL );
}
#endif

View file

@ -0,0 +1,251 @@
/**************************************************************************
*
* Copyright 2007-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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/*
* Rasterization for binned triangles within a tile
*/
#include <limits.h>
#include "util/u_math.h"
#include "lp_debug.h"
#include "lp_perf.h"
#include "lp_rast_priv.h"
#include "lp_tile_soa.h"
/**
* Map an index in [0,15] to an x,y position, multiplied by 4.
* This is used to get the position of each subtile in a 4x4
* grid of edge step values.
* Note: we can use some bit twiddling to compute these values instead
* of using a look-up table, but there's no measurable performance
* difference.
*/
static const int pos_table4[16][2] = {
{ 0, 0 },
{ 4, 0 },
{ 0, 4 },
{ 4, 4 },
{ 8, 0 },
{ 12, 0 },
{ 8, 4 },
{ 12, 4 },
{ 0, 8 },
{ 4, 8 },
{ 0, 12 },
{ 4, 12 },
{ 8, 8 },
{ 12, 8 },
{ 8, 12 },
{ 12, 12 }
};
static const int pos_table16[16][2] = {
{ 0, 0 },
{ 16, 0 },
{ 0, 16 },
{ 16, 16 },
{ 32, 0 },
{ 48, 0 },
{ 32, 16 },
{ 48, 16 },
{ 0, 32 },
{ 16, 32 },
{ 0, 48 },
{ 16, 48 },
{ 32, 32 },
{ 48, 32 },
{ 32, 48 },
{ 48, 48 }
};
/**
* Shade all pixels in a 4x4 block.
*/
static void
block_full_4( struct lp_rasterizer_task *rast_task,
const struct lp_rast_triangle *tri,
int x, int y )
{
lp_rast_shade_quads_all(rast_task->rast,
rast_task->thread_index,
&tri->inputs,
x, y);
}
/**
* Shade all pixels in a 16x16 block.
*/
static void
block_full_16( struct lp_rasterizer_task *rast_task,
const struct lp_rast_triangle *tri,
int x, int y )
{
unsigned ix, iy;
assert(x % 16 == 0);
assert(y % 16 == 0);
for (iy = 0; iy < 16; iy += 4)
for (ix = 0; ix < 16; ix += 4)
block_full_4(rast_task, tri, x + ix, y + iy);
}
/**
* Pass the 4x4 pixel block to the shader function.
* Determination of which of the 16 pixels lies inside the triangle
* will be done as part of the fragment shader.
*/
static void
do_block_4( struct lp_rasterizer_task *rast_task,
const struct lp_rast_triangle *tri,
int x, int y,
int c1,
int c2,
int c3 )
{
lp_rast_shade_quads(rast_task->rast,
rast_task->thread_index,
&tri->inputs,
x, y,
-c1, -c2, -c3);
}
/**
* Evaluate a 16x16 block of pixels to determine which 4x4 subblocks are in/out
* of the triangle's bounds.
*/
static void
do_block_16( struct lp_rasterizer_task *rast_task,
const struct lp_rast_triangle *tri,
int x, int y,
int c1,
int c2,
int c3 )
{
const int eo1 = tri->eo1 * 4;
const int eo2 = tri->eo2 * 4;
const int eo3 = tri->eo3 * 4;
const int *step0 = tri->inputs.step[0];
const int *step1 = tri->inputs.step[1];
const int *step2 = tri->inputs.step[2];
int i;
assert(x % 16 == 0);
assert(y % 16 == 0);
for (i = 0; i < 16; i++) {
int cx1 = c1 + step0[i] * 4;
int cx2 = c2 + step1[i] * 4;
int cx3 = c3 + step2[i] * 4;
if (cx1 + eo1 < 0 ||
cx2 + eo2 < 0 ||
cx3 + eo3 < 0) {
/* the block is completely outside the triangle - nop */
LP_COUNT(nr_empty_4);
}
else {
int px = x + pos_table4[i][0];
int py = y + pos_table4[i][1];
/* Don't bother testing if the 4x4 block is entirely in/out of
* the triangle. It's a little faster to do it in the jit code.
*/
LP_COUNT(nr_non_empty_4);
do_block_4(rast_task, tri, px, py, cx1, cx2, cx3);
}
}
}
/**
* Scan the tile in chunks and figure out which pixels to rasterize
* for this triangle.
*/
void
lp_rast_triangle( struct lp_rasterizer *rast,
unsigned thread_index,
const union lp_rast_cmd_arg arg )
{
struct lp_rasterizer_task *rast_task = &rast->tasks[thread_index];
const struct lp_rast_triangle *tri = arg.triangle;
int x = rast_task->x;
int y = rast_task->y;
unsigned i;
int c1 = tri->c1 + tri->dx12 * y - tri->dy12 * x;
int c2 = tri->c2 + tri->dx23 * y - tri->dy23 * x;
int c3 = tri->c3 + tri->dx31 * y - tri->dy31 * x;
int ei1 = tri->ei1 * 16;
int ei2 = tri->ei2 * 16;
int ei3 = tri->ei3 * 16;
int eo1 = tri->eo1 * 16;
int eo2 = tri->eo2 * 16;
int eo3 = tri->eo3 * 16;
LP_DBG(DEBUG_RAST, "lp_rast_triangle\n");
/* Walk over the tile to build a list of 4x4 pixel blocks which will
* be filled/shaded. We do this at two granularities: 16x16 blocks
* and then 4x4 blocks.
*/
for (i = 0; i < 16; i++) {
int cx1 = c1 + (tri->inputs.step[0][i] * 16);
int cx2 = c2 + (tri->inputs.step[1][i] * 16);
int cx3 = c3 + (tri->inputs.step[2][i] * 16);
if (cx1 + eo1 < 0 ||
cx2 + eo2 < 0 ||
cx3 + eo3 < 0) {
/* the block is completely outside the triangle - nop */
LP_COUNT(nr_empty_16);
}
else {
int px = x + pos_table16[i][0];
int py = y + pos_table16[i][1];
if (cx1 + ei1 > 0 &&
cx2 + ei2 > 0 &&
cx3 + ei3 > 0) {
/* the block is completely inside the triangle */
LP_COUNT(nr_fully_covered_16);
block_full_16(rast_task, tri, px, py);
}
else {
/* the block is partially in/out of the triangle */
LP_COUNT(nr_partially_covered_16);
do_block_16(rast_task, tri, px, py, cx1, cx2, cx3);
}
}
}
}

View file

@ -0,0 +1,392 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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_math.h"
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "util/u_simple_list.h"
#include "lp_scene.h"
struct lp_scene *
lp_scene_create(void)
{
struct lp_scene *scene = CALLOC_STRUCT(lp_scene);
if (scene)
lp_scene_init(scene);
return scene;
}
void
lp_scene_destroy(struct lp_scene *scene)
{
lp_scene_reset(scene);
lp_scene_free_bin_data(scene);
FREE(scene);
}
void
lp_scene_init(struct lp_scene *scene)
{
unsigned i, j;
for (i = 0; i < TILES_X; i++)
for (j = 0; j < TILES_Y; j++) {
struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
bin->commands.head = bin->commands.tail = CALLOC_STRUCT(cmd_block);
}
scene->data.head =
scene->data.tail = CALLOC_STRUCT(data_block);
make_empty_list(&scene->textures);
pipe_mutex_init(scene->mutex);
}
/**
* Check if the scene's bins are all empty.
* For debugging purposes.
*/
boolean
lp_scene_is_empty(struct lp_scene *scene )
{
unsigned x, y;
for (y = 0; y < TILES_Y; y++) {
for (x = 0; x < TILES_X; x++) {
const struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
const struct cmd_block_list *list = &bin->commands;
if (list->head != list->tail || list->head->count > 0) {
return FALSE;
}
}
}
return TRUE;
}
void
lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y)
{
struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
struct cmd_block_list *list = &bin->commands;
struct cmd_block *block;
struct cmd_block *tmp;
for (block = list->head; block != list->tail; block = tmp) {
tmp = block->next;
FREE(block);
}
assert(list->tail->next == NULL);
list->head = list->tail;
list->head->count = 0;
}
/**
* Set scene to empty state.
*/
void
lp_scene_reset(struct lp_scene *scene )
{
unsigned i, j;
/* Free all but last binner command lists:
*/
for (i = 0; i < scene->tiles_x; i++) {
for (j = 0; j < scene->tiles_y; j++) {
lp_scene_bin_reset(scene, i, j);
}
}
assert(lp_scene_is_empty(scene));
/* Free all but last binned data block:
*/
{
struct data_block_list *list = &scene->data;
struct data_block *block, *tmp;
for (block = list->head; block != list->tail; block = tmp) {
tmp = block->next;
FREE(block);
}
assert(list->tail->next == NULL);
list->head = list->tail;
list->head->used = 0;
}
/* Release texture refs
*/
{
struct texture_ref *ref, *next, *ref_list = &scene->textures;
for (ref = ref_list->next; ref != ref_list; ref = next) {
next = next_elem(ref);
pipe_texture_reference(&ref->texture, NULL);
FREE(ref);
}
make_empty_list(ref_list);
}
}
/**
* Free all data associated with the given bin, but don't free(scene).
*/
void
lp_scene_free_bin_data(struct lp_scene *scene)
{
unsigned i, j;
for (i = 0; i < TILES_X; i++)
for (j = 0; j < TILES_Y; j++) {
struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
/* lp_reset_scene() should have been already called */
assert(bin->commands.head == bin->commands.tail);
FREE(bin->commands.head);
bin->commands.head = NULL;
bin->commands.tail = NULL;
}
FREE(scene->data.head);
scene->data.head = NULL;
pipe_mutex_destroy(scene->mutex);
}
void
lp_scene_set_framebuffer_size( struct lp_scene *scene,
unsigned width, unsigned height )
{
assert(lp_scene_is_empty(scene));
scene->tiles_x = align(width, TILE_SIZE) / TILE_SIZE;
scene->tiles_y = align(height, TILE_SIZE) / TILE_SIZE;
}
void
lp_bin_new_cmd_block( struct cmd_block_list *list )
{
struct cmd_block *block = MALLOC_STRUCT(cmd_block);
list->tail->next = block;
list->tail = block;
block->next = NULL;
block->count = 0;
}
void
lp_bin_new_data_block( struct data_block_list *list )
{
struct data_block *block = MALLOC_STRUCT(data_block);
list->tail->next = block;
list->tail = block;
block->next = NULL;
block->used = 0;
}
/** Return number of bytes used for all bin data within a scene */
unsigned
lp_scene_data_size( const struct lp_scene *scene )
{
unsigned size = 0;
const struct data_block *block;
for (block = scene->data.head; block; block = block->next) {
size += block->used;
}
return size;
}
/** Return number of bytes used for a single bin */
unsigned
lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y )
{
struct cmd_bin *bin = lp_scene_get_bin((struct lp_scene *) scene, x, y);
const struct cmd_block *cmd;
unsigned size = 0;
for (cmd = bin->commands.head; cmd; cmd = cmd->next) {
size += (cmd->count *
(sizeof(lp_rast_cmd) + sizeof(union lp_rast_cmd_arg)));
}
return size;
}
/**
* Add a reference to a texture by the scene.
*/
void
lp_scene_texture_reference( struct lp_scene *scene,
struct pipe_texture *texture )
{
struct texture_ref *ref = CALLOC_STRUCT(texture_ref);
if (ref) {
struct texture_ref *ref_list = &scene->textures;
pipe_texture_reference(&ref->texture, texture);
insert_at_tail(ref_list, ref);
}
}
/**
* Does this scene have a reference to the given texture?
*/
boolean
lp_scene_is_textured_referenced( const struct lp_scene *scene,
const struct pipe_texture *texture )
{
const struct texture_ref *ref_list = &scene->textures;
const struct texture_ref *ref;
foreach (ref, ref_list) {
if (ref->texture == texture)
return TRUE;
}
return FALSE;
}
/**
* Return last command in the bin
*/
static lp_rast_cmd
lp_get_last_command( const struct cmd_bin *bin )
{
const struct cmd_block *tail = bin->commands.tail;
const unsigned i = tail->count;
if (i > 0)
return tail->cmd[i - 1];
else
return NULL;
}
/**
* Replace the arg of the last command in the bin.
*/
static void
lp_replace_last_command_arg( struct cmd_bin *bin,
const union lp_rast_cmd_arg arg )
{
struct cmd_block *tail = bin->commands.tail;
const unsigned i = tail->count;
assert(i > 0);
tail->arg[i - 1] = arg;
}
/**
* Put a state-change command into all bins.
* If we find that the last command in a bin was also a state-change
* command, we can simply replace that one with the new one.
*/
void
lp_scene_bin_state_command( struct lp_scene *scene,
lp_rast_cmd cmd,
const union lp_rast_cmd_arg arg )
{
unsigned i, j;
for (i = 0; i < scene->tiles_x; i++) {
for (j = 0; j < scene->tiles_y; j++) {
struct cmd_bin *bin = lp_scene_get_bin(scene, i, j);
lp_rast_cmd last_cmd = lp_get_last_command(bin);
if (last_cmd == cmd) {
lp_replace_last_command_arg(bin, arg);
}
else {
lp_scene_bin_command( scene, i, j, cmd, arg );
}
}
}
}
/** advance curr_x,y to the next bin */
static boolean
next_bin(struct lp_scene *scene)
{
scene->curr_x++;
if (scene->curr_x >= scene->tiles_x) {
scene->curr_x = 0;
scene->curr_y++;
}
if (scene->curr_y >= scene->tiles_y) {
/* no more bins */
return FALSE;
}
return TRUE;
}
void
lp_scene_bin_iter_begin( struct lp_scene *scene )
{
scene->curr_x = scene->curr_y = -1;
}
/**
* Return pointer to next bin to be rendered.
* The lp_scene::curr_x and ::curr_y fields will be advanced.
* Multiple rendering threads will call this function to get a chunk
* of work (a bin) to work on.
*/
struct cmd_bin *
lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y )
{
struct cmd_bin *bin = NULL;
pipe_mutex_lock(scene->mutex);
if (scene->curr_x < 0) {
/* first bin */
scene->curr_x = 0;
scene->curr_y = 0;
}
else if (!next_bin(scene)) {
/* no more bins left */
goto end;
}
bin = lp_scene_get_bin(scene, scene->curr_x, scene->curr_y);
*bin_x = scene->curr_x;
*bin_y = scene->curr_y;
end:
/*printf("return bin %p at %d, %d\n", (void *) bin, *bin_x, *bin_y);*/
pipe_mutex_unlock(scene->mutex);
return bin;
}

View file

@ -0,0 +1,301 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Binner data structures and bin-related functions.
* Note: the "setup" code is concerned with building scenes while
* The "rast" code is concerned with consuming/executing scenes.
*/
#ifndef LP_SCENE_H
#define LP_SCENE_H
#include "os/os_thread.h"
#include "lp_tile_soa.h"
#include "lp_rast.h"
/* We're limited to 2K by 2K for 32bit fixed point rasterization.
* Will need a 64-bit version for larger framebuffers.
*/
#define MAXHEIGHT 2048
#define MAXWIDTH 2048
#define TILES_X (MAXWIDTH / TILE_SIZE)
#define TILES_Y (MAXHEIGHT / TILE_SIZE)
#define CMD_BLOCK_MAX 128
#define DATA_BLOCK_SIZE (16 * 1024 - sizeof(unsigned) - sizeof(void *))
/* switch to a non-pointer value for this:
*/
typedef void (*lp_rast_cmd)( struct lp_rasterizer *,
unsigned thread_index,
const union lp_rast_cmd_arg );
struct cmd_block {
lp_rast_cmd cmd[CMD_BLOCK_MAX];
union lp_rast_cmd_arg arg[CMD_BLOCK_MAX];
unsigned count;
struct cmd_block *next;
};
struct data_block {
ubyte data[DATA_BLOCK_SIZE];
unsigned used;
struct data_block *next;
};
struct cmd_block_list {
struct cmd_block *head;
struct cmd_block *tail;
};
/**
* For each screen tile we have one of these bins.
*/
struct cmd_bin {
struct cmd_block_list commands;
};
/**
* This stores bulk data which is shared by all bins within a scene.
* Examples include triangle data and state data. The commands in
* the per-tile bins will point to chunks of data in this structure.
*/
struct data_block_list {
struct data_block *head;
struct data_block *tail;
};
/** List of texture references */
struct texture_ref {
struct pipe_texture *texture;
struct texture_ref *prev, *next; /**< linked list w/ u_simple_list.h */
};
/**
* All bins and bin data are contained here.
* Per-bin data goes into the 'tile' bins.
* Shared data goes into the 'data' buffer.
*
* When there are multiple threads, will want to double-buffer between
* scenes:
*/
struct lp_scene {
struct cmd_bin tile[TILES_X][TILES_Y];
struct data_block_list data;
/** the framebuffer to render the scene into */
struct pipe_framebuffer_state fb;
/** list of textures referenced by the scene commands */
struct texture_ref textures;
boolean write_depth;
/**
* Number of active tiles in each dimension.
* This basically the framebuffer size divided by tile size
*/
unsigned tiles_x, tiles_y;
int curr_x, curr_y; /**< for iterating over bins */
pipe_mutex mutex;
};
struct lp_scene *lp_scene_create(void);
void lp_scene_destroy(struct lp_scene *scene);
void lp_scene_init(struct lp_scene *scene);
boolean lp_scene_is_empty(struct lp_scene *scene );
void lp_scene_reset(struct lp_scene *scene );
void lp_scene_free_bin_data(struct lp_scene *scene);
void lp_scene_set_framebuffer_size( struct lp_scene *scene,
unsigned width, unsigned height );
void lp_bin_new_data_block( struct data_block_list *list );
void lp_bin_new_cmd_block( struct cmd_block_list *list );
unsigned lp_scene_data_size( const struct lp_scene *scene );
unsigned lp_scene_bin_size( const struct lp_scene *scene, unsigned x, unsigned y );
void lp_scene_texture_reference( struct lp_scene *scene,
struct pipe_texture *texture );
boolean lp_scene_is_textured_referenced( const struct lp_scene *scene,
const struct pipe_texture *texture );
/**
* Allocate space for a command/data in the bin's data buffer.
* Grow the block list if needed.
*/
static INLINE void *
lp_scene_alloc( struct lp_scene *scene, unsigned size)
{
struct data_block_list *list = &scene->data;
if (list->tail->used + size > DATA_BLOCK_SIZE) {
lp_bin_new_data_block( list );
}
{
struct data_block *tail = list->tail;
ubyte *data = tail->data + tail->used;
tail->used += size;
return data;
}
}
/**
* As above, but with specific alignment.
*/
static INLINE void *
lp_scene_alloc_aligned( struct lp_scene *scene, unsigned size,
unsigned alignment )
{
struct data_block_list *list = &scene->data;
if (list->tail->used + size + alignment - 1 > DATA_BLOCK_SIZE) {
lp_bin_new_data_block( list );
}
{
struct data_block *tail = list->tail;
ubyte *data = tail->data + tail->used;
unsigned offset = (((uintptr_t)data + alignment - 1) & ~(alignment - 1)) - (uintptr_t)data;
tail->used += offset + size;
return data + offset;
}
}
/* Put back data if we decide not to use it, eg. culled triangles.
*/
static INLINE void
lp_scene_putback_data( struct lp_scene *scene, unsigned size)
{
struct data_block_list *list = &scene->data;
assert(list->tail->used >= size);
list->tail->used -= size;
}
/** Return pointer to a particular tile's bin. */
static INLINE struct cmd_bin *
lp_scene_get_bin(struct lp_scene *scene, unsigned x, unsigned y)
{
return &scene->tile[x][y];
}
/** Remove all commands from a bin */
void
lp_scene_bin_reset(struct lp_scene *scene, unsigned x, unsigned y);
/* Add a command to bin[x][y].
*/
static INLINE void
lp_scene_bin_command( struct lp_scene *scene,
unsigned x, unsigned y,
lp_rast_cmd cmd,
union lp_rast_cmd_arg arg )
{
struct cmd_bin *bin = lp_scene_get_bin(scene, x, y);
struct cmd_block_list *list = &bin->commands;
assert(x < scene->tiles_x);
assert(y < scene->tiles_y);
if (list->tail->count == CMD_BLOCK_MAX) {
lp_bin_new_cmd_block( list );
}
{
struct cmd_block *tail = list->tail;
unsigned i = tail->count;
tail->cmd[i] = cmd;
tail->arg[i] = arg;
tail->count++;
}
}
/* Add a command to all active bins.
*/
static INLINE void
lp_scene_bin_everywhere( struct lp_scene *scene,
lp_rast_cmd cmd,
const union lp_rast_cmd_arg arg )
{
unsigned i, j;
for (i = 0; i < scene->tiles_x; i++)
for (j = 0; j < scene->tiles_y; j++)
lp_scene_bin_command( scene, i, j, cmd, arg );
}
void
lp_scene_bin_state_command( struct lp_scene *scene,
lp_rast_cmd cmd,
const union lp_rast_cmd_arg arg );
static INLINE unsigned
lp_scene_get_num_bins( const struct lp_scene *scene )
{
return scene->tiles_x * scene->tiles_y;
}
void
lp_scene_bin_iter_begin( struct lp_scene *scene );
struct cmd_bin *
lp_scene_bin_iter_next( struct lp_scene *scene, int *bin_x, int *bin_y );
#endif /* LP_BIN_H */

View file

@ -0,0 +1,122 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Scene queue. We'll use two queues. One contains "full" scenes which
* are produced by the "setup" code. The other contains "empty" scenes
* which are produced by the "rast" code when it finishes rendering a scene.
*/
#include "util/u_ringbuffer.h"
#include "util/u_memory.h"
#include "lp_scene_queue.h"
#define MAX_SCENE_QUEUE 4
struct scene_packet {
struct util_packet header;
struct lp_scene *scene;
};
/**
* A queue of scenes
*/
struct lp_scene_queue
{
struct util_ringbuffer *ring;
};
/** Allocate a new scene queue */
struct lp_scene_queue *
lp_scene_queue_create(void)
{
struct lp_scene_queue *queue = CALLOC_STRUCT(lp_scene_queue);
if (queue == NULL)
return NULL;
queue->ring = util_ringbuffer_create( MAX_SCENE_QUEUE *
sizeof( struct scene_packet ) / 4);
if (queue->ring == NULL)
goto fail;
return queue;
fail:
FREE(queue);
return NULL;
}
/** Delete a scene queue */
void
lp_scene_queue_destroy(struct lp_scene_queue *queue)
{
util_ringbuffer_destroy(queue->ring);
FREE(queue);
}
/** Remove first lp_scene from head of queue */
struct lp_scene *
lp_scene_dequeue(struct lp_scene_queue *queue, boolean wait)
{
struct scene_packet packet;
enum pipe_error ret;
ret = util_ringbuffer_dequeue(queue->ring,
&packet.header,
sizeof packet / 4,
wait );
if (ret != PIPE_OK)
return NULL;
return packet.scene;
}
/** Add an lp_scene to tail of queue */
void
lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene)
{
struct scene_packet packet;
packet.header.dwords = sizeof packet / 4;
packet.header.data24 = 0;
packet.scene = scene;
util_ringbuffer_enqueue(queue->ring, &packet.header);
}

View file

@ -0,0 +1,51 @@
/**************************************************************************
*
* Copyright 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#ifndef LP_SCENE_QUEUE
#define LP_SCENE_QUEUE
struct lp_scene_queue;
struct lp_scene;
struct lp_scene_queue *
lp_scene_queue_create(void);
void
lp_scene_queue_destroy(struct lp_scene_queue *queue);
struct lp_scene *
lp_scene_dequeue(struct lp_scene_queue *queue, boolean wait);
void
lp_scene_enqueue(struct lp_scene_queue *queue, struct lp_scene *scene);
#endif /* LP_BIN_QUEUE */

View file

@ -33,6 +33,7 @@
#include "lp_texture.h"
#include "lp_buffer.h"
#include "lp_fence.h"
#include "lp_winsys.h"
#include "lp_jit.h"
#include "lp_screen.h"
@ -51,6 +52,10 @@ static const struct debug_named_value lp_debug_flags[] = {
{ "query", DEBUG_QUERY },
{ "screen", DEBUG_SCREEN },
{ "jit", DEBUG_JIT },
{ "show_tiles", DEBUG_SHOW_TILES },
{ "show_subtiles", DEBUG_SHOW_SUBTILES },
{ "counters", DEBUG_COUNTERS },
{ "nopt", DEBUG_NO_LLVM_OPT },
{NULL, 0}
};
#endif
@ -309,6 +314,7 @@ llvmpipe_create_screen(struct llvmpipe_winsys *winsys)
llvmpipe_init_screen_texture_funcs(&screen->base);
llvmpipe_init_screen_buffer_funcs(&screen->base);
llvmpipe_init_screen_fence_funcs(&screen->base);
lp_jit_screen_init(screen);

File diff suppressed because it is too large Load diff

View file

@ -27,27 +27,113 @@
#ifndef LP_SETUP_H
#define LP_SETUP_H
struct setup_context;
struct llvmpipe_context;
#include "pipe/p_compiler.h"
#include "lp_jit.h"
struct draw_context;
struct vertex_info;
enum lp_interp {
LP_INTERP_CONSTANT,
LP_INTERP_LINEAR,
LP_INTERP_PERSPECTIVE,
LP_INTERP_POSITION,
LP_INTERP_FACING
};
/* Describes how to generate all the fragment shader inputs from the
* the vertices passed into our triangle/line/point functions.
*
* Vertices are treated as an array of float[4] values, indexed by
* src_index.
*/
struct lp_shader_input {
enum lp_interp interp; /* how to interpolate values */
unsigned src_index; /* where to find values in incoming vertices */
};
struct pipe_texture;
struct pipe_surface;
struct pipe_buffer;
struct pipe_blend_color;
struct pipe_screen;
struct pipe_framebuffer_state;
struct lp_fragment_shader;
struct lp_jit_context;
struct setup_context *
lp_setup_create( struct pipe_screen *screen,
struct draw_context *draw );
void
lp_setup_clear(struct setup_context *setup,
const float *clear_color,
double clear_depth,
unsigned clear_stencil,
unsigned flags);
struct pipe_fence_handle *
lp_setup_fence( struct setup_context *setup );
void
lp_setup_flush( struct setup_context *setup,
unsigned flags );
void
lp_setup_bind_framebuffer( struct setup_context *setup,
const struct pipe_framebuffer_state *fb );
void
llvmpipe_setup_tri( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4] );
lp_setup_set_triangle_state( struct setup_context *setup,
unsigned cullmode,
boolean front_is_ccw,
boolean scissor );
void
llvmpipe_setup_line(struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4]);
lp_setup_set_fs_inputs( struct setup_context *setup,
const struct lp_shader_input *interp,
unsigned nr );
void
llvmpipe_setup_point( struct setup_context *setup,
const float (*v0)[4] );
lp_setup_set_fs_functions( struct setup_context *setup,
lp_jit_frag_func jit_function0,
lp_jit_frag_func jit_function1,
boolean opaque );
void
lp_setup_set_fs_constants(struct setup_context *setup,
struct pipe_buffer *buffer);
struct setup_context *llvmpipe_setup_create_context( struct llvmpipe_context *llvmpipe );
void llvmpipe_setup_prepare( struct setup_context *setup );
void llvmpipe_setup_destroy_context( struct setup_context *setup );
void
lp_setup_set_alpha_ref_value( struct setup_context *setup,
float alpha_ref_value );
void
lp_setup_set_blend_color( struct setup_context *setup,
const struct pipe_blend_color *blend_color );
void
lp_setup_set_scissor( struct setup_context *setup,
const struct pipe_scissor_state *scissor );
void
lp_setup_set_sampler_textures( struct setup_context *setup,
unsigned num, struct pipe_texture **texture);
unsigned
lp_setup_is_texture_referenced( const struct setup_context *setup,
const struct pipe_texture *texture );
void
lp_setup_set_flatshade_first( struct setup_context *setup,
boolean flatshade_first );
void
lp_setup_set_vertex_info( struct setup_context *setup,
struct vertex_info *info );
#endif

View file

@ -0,0 +1,159 @@
/**************************************************************************
*
* Copyright 2007-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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* The setup code is concerned with point/line/triangle setup and
* putting commands/data into the bins.
*/
#ifndef LP_SETUP_CONTEXT_H
#define LP_SETUP_CONTEXT_H
#include "lp_setup.h"
#include "lp_rast.h"
#include "lp_tile_soa.h" /* for TILE_SIZE */
#include "lp_scene.h"
#include "draw/draw_vbuf.h"
#define LP_SETUP_NEW_FS 0x01
#define LP_SETUP_NEW_CONSTANTS 0x02
#define LP_SETUP_NEW_BLEND_COLOR 0x04
#define LP_SETUP_NEW_SCISSOR 0x08
struct lp_scene_queue;
/** Max number of scenes */
#define MAX_SCENES 2
/**
* Point/line/triangle setup context.
* Note: "stored" below indicates data which is stored in the bins,
* not arbitrary malloc'd memory.
*
*
* Subclass of vbuf_render, plugged directly into the draw module as
* the rendering backend.
*/
struct setup_context
{
struct vbuf_render base;
struct vertex_info *vertex_info;
uint prim;
uint vertex_size;
uint nr_vertices;
uint vertex_buffer_size;
void *vertex_buffer;
/* Final pipeline stage for draw module. Draw module should
* create/install this itself now.
*/
struct draw_stage *vbuf;
struct lp_rasterizer *rast;
struct lp_scene *scenes[MAX_SCENES]; /**< all the scenes */
struct lp_scene *scene; /**< current scene being built */
struct lp_scene_queue *empty_scenes; /**< queue of empty scenes */
boolean flatshade_first;
boolean ccw_is_frontface;
boolean scissor_test;
unsigned cullmode;
struct pipe_framebuffer_state fb;
struct {
unsigned flags;
union lp_rast_cmd_arg color; /**< lp_rast_clear_color() cmd */
union lp_rast_cmd_arg zstencil; /**< lp_rast_clear_zstencil() cmd */
} clear;
enum {
SETUP_FLUSHED,
SETUP_CLEARED,
SETUP_ACTIVE
} state;
struct {
struct lp_shader_input input[PIPE_MAX_ATTRIBS];
unsigned nr_inputs;
const struct lp_rast_state *stored; /**< what's in the scene */
struct lp_rast_state current; /**< currently set state */
} fs;
/** fragment shader constants */
struct {
struct pipe_buffer *current;
unsigned stored_size;
const void *stored_data;
} constants;
struct {
struct pipe_blend_color current;
uint8_t *stored;
} blend_color;
struct {
struct pipe_scissor_state current;
const void *stored;
} scissor;
unsigned dirty; /**< bitmask of LP_SETUP_NEW_x bits */
void (*point)( struct setup_context *,
const float (*v0)[4]);
void (*line)( struct setup_context *,
const float (*v0)[4],
const float (*v1)[4]);
void (*triangle)( struct setup_context *,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4]);
};
void lp_setup_choose_triangle( struct setup_context *setup );
void lp_setup_choose_line( struct setup_context *setup );
void lp_setup_choose_point( struct setup_context *setup );
struct lp_scene *lp_setup_get_current_scene(struct setup_context *setup);
void lp_setup_init_vbuf(struct setup_context *setup);
void lp_setup_update_state( struct setup_context *setup );
void lp_setup_destroy( struct setup_context *setup );
#endif

View file

@ -1,8 +1,8 @@
/**************************************************************************
*
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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
@ -10,11 +10,11 @@
* distribute, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
@ -22,50 +22,26 @@
* 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.
*
*
**************************************************************************/
#ifndef LP_TILE_CACHE_H
#define LP_TILE_CACHE_H
/*
* Binning code for lines
*/
#include "lp_setup_context.h"
static void line_nop( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4] )
{
}
#include "pipe/p_compiler.h"
#include "lp_tile_soa.h"
void
lp_setup_choose_line( struct setup_context *setup )
{
setup->line = line_nop;
}
struct llvmpipe_tile_cache; /* opaque */
extern struct llvmpipe_tile_cache *
lp_create_tile_cache( struct pipe_screen *screen );
extern void
lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc);
extern void
lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
struct pipe_surface *lps);
extern struct pipe_surface *
lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc);
extern void
lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc);
extern void
lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc);
extern void
lp_flush_tile_cache(struct llvmpipe_tile_cache *tc);
extern void
lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
uint clearValue);
extern void *
lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
unsigned x, unsigned y );
#endif /* LP_TILE_CACHE_H */

View file

@ -1,8 +1,8 @@
/**************************************************************************
*
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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
@ -10,11 +10,11 @@
* distribute, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
@ -22,17 +22,25 @@
* 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.
*
*
**************************************************************************/
#ifndef LP_VBUF_H
#define LP_VBUF_H
/*
* Binning code for points
*/
#include "lp_setup_context.h"
static void point_nop( struct setup_context *setup,
const float (*v0)[4] )
{
}
struct llvmpipe_context;
extern struct vbuf_render *
lp_create_vbuf_backend(struct llvmpipe_context *llvmpipe);
void
lp_setup_choose_point( struct setup_context *setup )
{
setup->point = point_nop;
}
#endif /* LP_VBUF_H */

View file

@ -0,0 +1,618 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/*
* Binning code for triangles
*/
#include "util/u_math.h"
#include "util/u_memory.h"
#include "lp_perf.h"
#include "lp_setup_context.h"
#include "lp_rast.h"
#define NUM_CHANNELS 4
/**
* Compute a0 for a constant-valued coefficient (GL_FLAT shading).
*/
static void constant_coef( struct lp_rast_triangle *tri,
unsigned slot,
const float value,
unsigned i )
{
tri->inputs.a0[slot][i] = value;
tri->inputs.dadx[slot][i] = 0.0f;
tri->inputs.dady[slot][i] = 0.0f;
}
/**
* Compute a0, dadx and dady for a linearly interpolated coefficient,
* for a triangle.
*/
static void linear_coef( struct lp_rast_triangle *tri,
float oneoverarea,
unsigned slot,
const float (*v1)[4],
const float (*v2)[4],
const float (*v3)[4],
unsigned vert_attr,
unsigned i)
{
float a1 = v1[vert_attr][i];
float a2 = v2[vert_attr][i];
float a3 = v3[vert_attr][i];
float da12 = a1 - a2;
float da31 = a3 - a1;
float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
tri->inputs.dadx[slot][i] = dadx;
tri->inputs.dady[slot][i] = dady;
/* calculate a0 as the value which would be sampled for the
* fragment at (0,0), taking into account that we want to sample at
* pixel centers, in other words (0.5, 0.5).
*
* this is neat but unfortunately not a good way to do things for
* triangles with very large values of dadx or dady as it will
* result in the subtraction and re-addition from a0 of a very
* large number, which means we'll end up loosing a lot of the
* fractional bits and precision from a0. the way to fix this is
* to define a0 as the sample at a pixel center somewhere near vmin
* instead - i'll switch to this later.
*/
tri->inputs.a0[slot][i] = (a1 -
(dadx * (v1[0][0] - 0.5f) +
dady * (v1[0][1] - 0.5f)));
}
/**
* Compute a0, dadx and dady for a perspective-corrected interpolant,
* for a triangle.
* We basically multiply the vertex value by 1/w before computing
* the plane coefficients (a0, dadx, dady).
* Later, when we compute the value at a particular fragment position we'll
* divide the interpolated value by the interpolated W at that fragment.
*/
static void perspective_coef( struct lp_rast_triangle *tri,
float oneoverarea,
unsigned slot,
const float (*v1)[4],
const float (*v2)[4],
const float (*v3)[4],
unsigned vert_attr,
unsigned i)
{
/* premultiply by 1/w (v[0][3] is always 1/w):
*/
float a1 = v1[vert_attr][i] * v1[0][3];
float a2 = v2[vert_attr][i] * v2[0][3];
float a3 = v3[vert_attr][i] * v3[0][3];
float da12 = a1 - a2;
float da31 = a3 - a1;
float dadx = (da12 * tri->dy31 - tri->dy12 * da31) * oneoverarea;
float dady = (da31 * tri->dx12 - tri->dx31 * da12) * oneoverarea;
tri->inputs.dadx[slot][i] = dadx;
tri->inputs.dady[slot][i] = dady;
tri->inputs.a0[slot][i] = (a1 -
(dadx * (v1[0][0] - 0.5f) +
dady * (v1[0][1] - 0.5f)));
}
/**
* Special coefficient setup for gl_FragCoord.
* X and Y are trivial
* Z and W are copied from position_coef which should have already been computed.
* We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
*/
static void
setup_fragcoord_coef(struct lp_rast_triangle *tri,
float oneoverarea,
unsigned slot,
const float (*v1)[4],
const float (*v2)[4],
const float (*v3)[4])
{
/*X*/
tri->inputs.a0[slot][0] = 0.0;
tri->inputs.dadx[slot][0] = 1.0;
tri->inputs.dady[slot][0] = 0.0;
/*Y*/
tri->inputs.a0[slot][1] = 0.0;
tri->inputs.dadx[slot][1] = 0.0;
tri->inputs.dady[slot][1] = 1.0;
/*Z*/
linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 2);
/*W*/
linear_coef(tri, oneoverarea, slot, v1, v2, v3, 0, 3);
}
static void setup_facing_coef( struct lp_rast_triangle *tri,
unsigned slot,
boolean frontface )
{
constant_coef( tri, slot, 1.0f - frontface, 0 );
constant_coef( tri, slot, 0.0f, 1 ); /* wasted */
constant_coef( tri, slot, 0.0f, 2 ); /* wasted */
constant_coef( tri, slot, 0.0f, 3 ); /* wasted */
}
/**
* Compute the tri->coef[] array dadx, dady, a0 values.
*/
static void setup_tri_coefficients( struct setup_context *setup,
struct lp_rast_triangle *tri,
float oneoverarea,
const float (*v1)[4],
const float (*v2)[4],
const float (*v3)[4],
boolean frontface)
{
unsigned slot;
/* The internal position input is in slot zero:
*/
setup_fragcoord_coef(tri, oneoverarea, 0, v1, v2, v3);
/* setup interpolation for all the remaining attributes:
*/
for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
unsigned vert_attr = setup->fs.input[slot].src_index;
unsigned i;
switch (setup->fs.input[slot].interp) {
case LP_INTERP_CONSTANT:
for (i = 0; i < NUM_CHANNELS; i++)
constant_coef(tri, slot+1, v3[vert_attr][i], i);
break;
case LP_INTERP_LINEAR:
for (i = 0; i < NUM_CHANNELS; i++)
linear_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
break;
case LP_INTERP_PERSPECTIVE:
for (i = 0; i < NUM_CHANNELS; i++)
perspective_coef(tri, oneoverarea, slot+1, v1, v2, v3, vert_attr, i);
break;
case LP_INTERP_POSITION:
/* XXX: fix me - duplicates the values in slot zero.
*/
setup_fragcoord_coef(tri, oneoverarea, slot+1, v1, v2, v3);
break;
case LP_INTERP_FACING:
setup_facing_coef(tri, slot+1, frontface);
break;
default:
assert(0);
}
}
}
static INLINE int subpixel_snap( float a )
{
return util_iround(FIXED_ONE * a - (FIXED_ONE / 2));
}
/**
* Alloc space for a new triangle plus the input.a0/dadx/dady arrays
* immediately after it.
* The memory is allocated from the per-scene pool, not per-tile.
* \param tri_size returns number of bytes allocated
* \param nr_inputs number of fragment shader inputs
* \return pointer to triangle space
*/
static INLINE struct lp_rast_triangle *
alloc_triangle(struct lp_scene *scene, unsigned nr_inputs, unsigned *tri_size)
{
unsigned input_array_sz = NUM_CHANNELS * (nr_inputs + 1) * sizeof(float);
struct lp_rast_triangle *tri;
unsigned bytes;
char *inputs;
assert(sizeof(*tri) % 16 == 0);
bytes = sizeof(*tri) + (3 * input_array_sz);
tri = lp_scene_alloc_aligned( scene, bytes, 16 );
inputs = (char *) (tri + 1);
tri->inputs.a0 = (float (*)[4]) inputs;
tri->inputs.dadx = (float (*)[4]) (inputs + input_array_sz);
tri->inputs.dady = (float (*)[4]) (inputs + 2 * input_array_sz);
*tri_size = bytes;
return tri;
}
/**
* Do basic setup for triangle rasterization and determine which
* framebuffer tiles are touched. Put the triangle in the scene's
* bins for the tiles which we overlap.
*/
static void
do_triangle_ccw(struct setup_context *setup,
const float (*v1)[4],
const float (*v2)[4],
const float (*v3)[4],
boolean frontfacing )
{
/* x/y positions in fixed point */
const int x1 = subpixel_snap(v1[0][0]);
const int x2 = subpixel_snap(v2[0][0]);
const int x3 = subpixel_snap(v3[0][0]);
const int y1 = subpixel_snap(v1[0][1]);
const int y2 = subpixel_snap(v2[0][1]);
const int y3 = subpixel_snap(v3[0][1]);
struct lp_scene *scene = lp_setup_get_current_scene(setup);
struct lp_rast_triangle *tri;
int area;
float oneoverarea;
int minx, maxx, miny, maxy;
unsigned tri_bytes;
tri = alloc_triangle(scene, setup->fs.nr_inputs, &tri_bytes);
tri->dx12 = x1 - x2;
tri->dx23 = x2 - x3;
tri->dx31 = x3 - x1;
tri->dy12 = y1 - y2;
tri->dy23 = y2 - y3;
tri->dy31 = y3 - y1;
area = (tri->dx12 * tri->dy31 - tri->dx31 * tri->dy12);
LP_COUNT(nr_tris);
/* Cull non-ccw and zero-sized triangles.
*
* XXX: subject to overflow??
*/
if (area <= 0) {
lp_scene_putback_data( scene, tri_bytes );
LP_COUNT(nr_culled_tris);
return;
}
/* Bounding rectangle (in pixels) */
minx = (MIN3(x1, x2, x3) + (FIXED_ONE-1)) >> FIXED_ORDER;
maxx = (MAX3(x1, x2, x3) + (FIXED_ONE-1)) >> FIXED_ORDER;
miny = (MIN3(y1, y2, y3) + (FIXED_ONE-1)) >> FIXED_ORDER;
maxy = (MAX3(y1, y2, y3) + (FIXED_ONE-1)) >> FIXED_ORDER;
if (setup->scissor_test) {
minx = MAX2(minx, setup->scissor.current.minx);
maxx = MIN2(maxx, setup->scissor.current.maxx);
miny = MAX2(miny, setup->scissor.current.miny);
maxy = MIN2(maxy, setup->scissor.current.maxy);
}
if (miny == maxy ||
minx == maxx) {
lp_scene_putback_data( scene, tri_bytes );
LP_COUNT(nr_culled_tris);
return;
}
/*
*/
oneoverarea = ((float)FIXED_ONE) / (float)area;
/* Setup parameter interpolants:
*/
setup_tri_coefficients( setup, tri, oneoverarea, v1, v2, v3, frontfacing );
/* half-edge constants, will be interated over the whole render target.
*/
tri->c1 = tri->dy12 * x1 - tri->dx12 * y1;
tri->c2 = tri->dy23 * x2 - tri->dx23 * y2;
tri->c3 = tri->dy31 * x3 - tri->dx31 * y3;
/* correct for top-left fill convention:
*/
if (tri->dy12 < 0 || (tri->dy12 == 0 && tri->dx12 > 0)) tri->c1++;
if (tri->dy23 < 0 || (tri->dy23 == 0 && tri->dx23 > 0)) tri->c2++;
if (tri->dy31 < 0 || (tri->dy31 == 0 && tri->dx31 > 0)) tri->c3++;
tri->dy12 *= FIXED_ONE;
tri->dy23 *= FIXED_ONE;
tri->dy31 *= FIXED_ONE;
tri->dx12 *= FIXED_ONE;
tri->dx23 *= FIXED_ONE;
tri->dx31 *= FIXED_ONE;
/* find trivial reject offsets for each edge for a single-pixel
* sized block. These will be scaled up at each recursive level to
* match the active blocksize. Scaling in this way works best if
* the blocks are square.
*/
tri->eo1 = 0;
if (tri->dy12 < 0) tri->eo1 -= tri->dy12;
if (tri->dx12 > 0) tri->eo1 += tri->dx12;
tri->eo2 = 0;
if (tri->dy23 < 0) tri->eo2 -= tri->dy23;
if (tri->dx23 > 0) tri->eo2 += tri->dx23;
tri->eo3 = 0;
if (tri->dy31 < 0) tri->eo3 -= tri->dy31;
if (tri->dx31 > 0) tri->eo3 += tri->dx31;
/* Calculate trivial accept offsets from the above.
*/
tri->ei1 = tri->dx12 - tri->dy12 - tri->eo1;
tri->ei2 = tri->dx23 - tri->dy23 - tri->eo2;
tri->ei3 = tri->dx31 - tri->dy31 - tri->eo3;
/* Fill in the inputs.step[][] arrays.
* We've manually unrolled some loops here.
*/
{
const int xstep1 = -tri->dy12;
const int xstep2 = -tri->dy23;
const int xstep3 = -tri->dy31;
const int ystep1 = tri->dx12;
const int ystep2 = tri->dx23;
const int ystep3 = tri->dx31;
#define SETUP_STEP(i, x, y) \
do { \
tri->inputs.step[0][i] = x * xstep1 + y * ystep1; \
tri->inputs.step[1][i] = x * xstep2 + y * ystep2; \
tri->inputs.step[2][i] = x * xstep3 + y * ystep3; \
} while (0)
SETUP_STEP(0, 0, 0);
SETUP_STEP(1, 1, 0);
SETUP_STEP(2, 0, 1);
SETUP_STEP(3, 1, 1);
SETUP_STEP(4, 2, 0);
SETUP_STEP(5, 3, 0);
SETUP_STEP(6, 2, 1);
SETUP_STEP(7, 3, 1);
SETUP_STEP(8, 0, 2);
SETUP_STEP(9, 1, 2);
SETUP_STEP(10, 0, 3);
SETUP_STEP(11, 1, 3);
SETUP_STEP(12, 2, 2);
SETUP_STEP(13, 3, 2);
SETUP_STEP(14, 2, 3);
SETUP_STEP(15, 3, 3);
#undef STEP
}
/*
* All fields of 'tri' are now set. The remaining code here is
* concerned with binning.
*/
/* Convert to tile coordinates:
*/
minx = minx / TILE_SIZE;
miny = miny / TILE_SIZE;
maxx = maxx / TILE_SIZE;
maxy = maxy / TILE_SIZE;
/* Clamp maxx, maxy to framebuffer size
*/
maxx = MIN2(maxx, scene->tiles_x - 1);
maxy = MIN2(maxy, scene->tiles_y - 1);
/* Determine which tile(s) intersect the triangle's bounding box
*/
if (miny == maxy && minx == maxx)
{
/* Triangle is contained in a single tile:
*/
lp_scene_bin_command( scene, minx, miny, lp_rast_triangle,
lp_rast_arg_triangle(tri) );
}
else
{
int c1 = (tri->c1 +
tri->dx12 * miny * TILE_SIZE -
tri->dy12 * minx * TILE_SIZE);
int c2 = (tri->c2 +
tri->dx23 * miny * TILE_SIZE -
tri->dy23 * minx * TILE_SIZE);
int c3 = (tri->c3 +
tri->dx31 * miny * TILE_SIZE -
tri->dy31 * minx * TILE_SIZE);
int ei1 = tri->ei1 << TILE_ORDER;
int ei2 = tri->ei2 << TILE_ORDER;
int ei3 = tri->ei3 << TILE_ORDER;
int eo1 = tri->eo1 << TILE_ORDER;
int eo2 = tri->eo2 << TILE_ORDER;
int eo3 = tri->eo3 << TILE_ORDER;
int xstep1 = -(tri->dy12 << TILE_ORDER);
int xstep2 = -(tri->dy23 << TILE_ORDER);
int xstep3 = -(tri->dy31 << TILE_ORDER);
int ystep1 = tri->dx12 << TILE_ORDER;
int ystep2 = tri->dx23 << TILE_ORDER;
int ystep3 = tri->dx31 << TILE_ORDER;
int x, y;
/* Test tile-sized blocks against the triangle.
* Discard blocks fully outside the tri. If the block is fully
* contained inside the tri, bin an lp_rast_shade_tile command.
* Else, bin a lp_rast_triangle command.
*/
for (y = miny; y <= maxy; y++)
{
int cx1 = c1;
int cx2 = c2;
int cx3 = c3;
boolean in = FALSE; /* are we inside the triangle? */
for (x = minx; x <= maxx; x++)
{
if (cx1 + eo1 < 0 ||
cx2 + eo2 < 0 ||
cx3 + eo3 < 0)
{
/* do nothing */
LP_COUNT(nr_empty_64);
if (in)
break; /* exiting triangle, all done with this row */
}
else if (cx1 + ei1 > 0 &&
cx2 + ei2 > 0 &&
cx3 + ei3 > 0)
{
/* triangle covers the whole tile- shade whole tile */
LP_COUNT(nr_fully_covered_64);
in = TRUE;
if(setup->fs.current.opaque) {
lp_scene_bin_reset( scene, x, y );
lp_scene_bin_command( scene, x, y,
lp_rast_set_state,
lp_rast_arg_state(setup->fs.stored) );
}
lp_scene_bin_command( scene, x, y,
lp_rast_shade_tile,
lp_rast_arg_inputs(&tri->inputs) );
}
else
{
/* rasterizer/shade partial tile */
LP_COUNT(nr_partially_covered_64);
in = TRUE;
lp_scene_bin_command( scene, x, y,
lp_rast_triangle,
lp_rast_arg_triangle(tri) );
}
/* Iterate cx values across the region:
*/
cx1 += xstep1;
cx2 += xstep2;
cx3 += xstep3;
}
/* Iterate c values down the region:
*/
c1 += ystep1;
c2 += ystep2;
c3 += ystep3;
}
}
}
static void triangle_cw( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4] )
{
do_triangle_ccw( setup, v1, v0, v2, !setup->ccw_is_frontface );
}
static void triangle_ccw( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4] )
{
do_triangle_ccw( setup, v0, v1, v2, setup->ccw_is_frontface );
}
static void triangle_both( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4] )
{
/* edge vectors e = v0 - v2, f = v1 - v2 */
const float ex = v0[0][0] - v2[0][0];
const float ey = v0[0][1] - v2[0][1];
const float fx = v1[0][0] - v2[0][0];
const float fy = v1[0][1] - v2[0][1];
/* det = cross(e,f).z */
if (ex * fy - ey * fx < 0.0f)
triangle_ccw( setup, v0, v1, v2 );
else
triangle_cw( setup, v0, v1, v2 );
}
static void triangle_nop( struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4],
const float (*v2)[4] )
{
}
void
lp_setup_choose_triangle( struct setup_context *setup )
{
switch (setup->cullmode) {
case PIPE_WINDING_NONE:
setup->triangle = triangle_both;
break;
case PIPE_WINDING_CCW:
setup->triangle = triangle_cw;
break;
case PIPE_WINDING_CW:
setup->triangle = triangle_ccw;
break;
default:
setup->triangle = triangle_nop;
break;
}
}

View file

@ -0,0 +1,520 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Interface between 'draw' module's output and the llvmpipe rasterizer/setup
* code. When the 'draw' module has finished filling a vertex buffer, the
* draw_arrays() functions below will be called. Loop over the vertices and
* call the point/line/tri setup functions.
*
* Authors
* Brian Paul
*/
#include "lp_setup_context.h"
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "util/u_memory.h"
#include "util/u_prim.h"
#define LP_MAX_VBUF_INDEXES 1024
#define LP_MAX_VBUF_SIZE 4096
/** cast wrapper */
static struct setup_context *
setup_context(struct vbuf_render *vbr)
{
return (struct setup_context *) vbr;
}
static const struct vertex_info *
lp_setup_get_vertex_info(struct vbuf_render *vbr)
{
struct setup_context *setup = setup_context(vbr);
return setup->vertex_info;
}
static boolean
lp_setup_allocate_vertices(struct vbuf_render *vbr,
ushort vertex_size, ushort nr_vertices)
{
struct setup_context *setup = setup_context(vbr);
unsigned size = vertex_size * nr_vertices;
if (setup->vertex_buffer_size < size) {
align_free(setup->vertex_buffer);
setup->vertex_buffer = align_malloc(size, 16);
setup->vertex_buffer_size = size;
}
setup->vertex_size = vertex_size;
setup->nr_vertices = nr_vertices;
return setup->vertex_buffer != NULL;
}
static void
lp_setup_release_vertices(struct vbuf_render *vbr)
{
/* keep the old allocation for next time */
}
static void *
lp_setup_map_vertices(struct vbuf_render *vbr)
{
struct setup_context *setup = setup_context(vbr);
return setup->vertex_buffer;
}
static void
lp_setup_unmap_vertices(struct vbuf_render *vbr,
ushort min_index,
ushort max_index )
{
struct setup_context *setup = setup_context(vbr);
assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
/* do nothing */
}
static boolean
lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
{
setup_context(vbr)->prim = prim;
return TRUE;
}
typedef const float (*const_float4_ptr)[4];
static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
int index,
int stride )
{
return (const_float4_ptr)((char *)vertex_buffer + index * stride);
}
/**
* draw elements / indexed primitives
*/
static void
lp_setup_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
{
struct setup_context *setup = setup_context(vbr);
const unsigned stride = setup->vertex_info->size * sizeof(float);
const void *vertex_buffer = setup->vertex_buffer;
unsigned i;
lp_setup_update_state(setup);
switch (setup->prim) {
case PIPE_PRIM_POINTS:
for (i = 0; i < nr; i++) {
setup->point( setup,
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINES:
for (i = 1; i < nr; i += 2) {
setup->line( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINE_STRIP:
for (i = 1; i < nr; i ++) {
setup->line( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
break;
case PIPE_PRIM_LINE_LOOP:
for (i = 1; i < nr; i ++) {
setup->line( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
if (nr) {
setup->line( setup,
get_vert(vertex_buffer, indices[nr-1], stride),
get_vert(vertex_buffer, indices[0], stride) );
}
break;
case PIPE_PRIM_TRIANGLES:
if (setup->flatshade_first) {
for (i = 2; i < nr; i += 3) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-2], stride) );
}
}
else {
for (i = 2; i < nr; i += 3) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_STRIP:
if (setup->flatshade_first) {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
get_vert(vertex_buffer, indices[i-(i&1)], stride),
get_vert(vertex_buffer, indices[i-2], stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_FAN:
if (setup->flatshade_first) {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[0], stride),
get_vert(vertex_buffer, indices[i-1], stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_QUADS:
if (setup->flatshade_first) {
for (i = 3; i < nr; i += 4) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
}
}
else {
for (i = 3; i < nr; i += 4) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_QUAD_STRIP:
if (setup->flatshade_first) {
for (i = 3; i < nr; i += 2) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride));
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-3], stride) );
}
}
else {
for (i = 3; i < nr; i += 2) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-2], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[i-3], stride),
get_vert(vertex_buffer, indices[i-0], stride) );
}
}
break;
case PIPE_PRIM_POLYGON:
/* Almost same as tri fan but the _first_ vertex specifies the flat
* shading color. Note that the first polygon vertex is passed as
* the last triangle vertex here.
* flatshade_first state makes no difference.
*/
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, indices[i-0], stride),
get_vert(vertex_buffer, indices[i-1], stride),
get_vert(vertex_buffer, indices[0], stride) );
}
break;
default:
assert(0);
}
}
/**
* This function is hit when the draw module is working in pass-through mode.
* It's up to us to convert the vertex array into point/line/tri prims.
*/
static void
lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
{
struct setup_context *setup = setup_context(vbr);
const unsigned stride = setup->vertex_info->size * sizeof(float);
const void *vertex_buffer =
(void *) get_vert(setup->vertex_buffer, start, stride);
unsigned i;
lp_setup_update_state(setup);
switch (setup->prim) {
case PIPE_PRIM_POINTS:
for (i = 0; i < nr; i++) {
setup->point( setup,
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINES:
for (i = 1; i < nr; i += 2) {
setup->line( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINE_STRIP:
for (i = 1; i < nr; i ++) {
setup->line( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
break;
case PIPE_PRIM_LINE_LOOP:
for (i = 1; i < nr; i ++) {
setup->line( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
if (nr) {
setup->line( setup,
get_vert(vertex_buffer, nr-1, stride),
get_vert(vertex_buffer, 0, stride) );
}
break;
case PIPE_PRIM_TRIANGLES:
if (setup->flatshade_first) {
for (i = 2; i < nr; i += 3) {
setup->triangle( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-2, stride) );
}
}
else {
for (i = 2; i < nr; i += 3) {
setup->triangle( setup,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_STRIP:
if (setup->flatshade_first) {
for (i = 2; i < nr; i++) {
setup->triangle( setup,
get_vert(vertex_buffer, i+(i&1)-1, stride),
get_vert(vertex_buffer, i-(i&1), stride),
get_vert(vertex_buffer, i-2, stride) );
}
}
else {
for (i = 2; i < nr; i++) {
setup->triangle( setup,
get_vert(vertex_buffer, i+(i&1)-2, stride),
get_vert(vertex_buffer, i-(i&1)-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_TRIANGLE_FAN:
if (setup->flatshade_first) {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, 0, stride),
get_vert(vertex_buffer, i-1, stride) );
}
}
else {
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, 0, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_QUADS:
if (setup->flatshade_first) {
for (i = 3; i < nr; i += 4) {
setup->triangle( setup,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride) );
setup->triangle( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-3, stride) );
}
}
else {
for (i = 3; i < nr; i += 4) {
setup->triangle( setup,
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride) );
setup->triangle( setup,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_QUAD_STRIP:
if (setup->flatshade_first) {
for (i = 3; i < nr; i += 2) {
setup->triangle( setup,
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride) );
setup->triangle( setup,
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, i-3, stride) );
}
}
else {
for (i = 3; i < nr; i += 2) {
setup->triangle( setup,
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-2, stride),
get_vert(vertex_buffer, i-0, stride) );
setup->triangle( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-3, stride),
get_vert(vertex_buffer, i-0, stride) );
}
}
break;
case PIPE_PRIM_POLYGON:
/* Almost same as tri fan but the _first_ vertex specifies the flat
* shading color. Note that the first polygon vertex is passed as
* the last triangle vertex here.
* flatshade_first state makes no difference.
*/
for (i = 2; i < nr; i += 1) {
setup->triangle( setup,
get_vert(vertex_buffer, i-1, stride),
get_vert(vertex_buffer, i-0, stride),
get_vert(vertex_buffer, 0, stride) );
}
break;
default:
assert(0);
}
}
static void
lp_setup_vbuf_destroy(struct vbuf_render *vbr)
{
lp_setup_destroy(setup_context(vbr));
}
/**
* Create the post-transform vertex handler for the given context.
*/
void
lp_setup_init_vbuf(struct setup_context *setup)
{
setup->base.max_indices = LP_MAX_VBUF_INDEXES;
setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
setup->base.get_vertex_info = lp_setup_get_vertex_info;
setup->base.allocate_vertices = lp_setup_allocate_vertices;
setup->base.map_vertices = lp_setup_map_vertices;
setup->base.unmap_vertices = lp_setup_unmap_vertices;
setup->base.set_primitive = lp_setup_set_primitive;
setup->base.draw = lp_setup_draw;
setup->base.draw_arrays = lp_setup_draw_arrays;
setup->base.release_vertices = lp_setup_release_vertices;
setup->base.destroy = lp_setup_vbuf_destroy;
}

View file

@ -54,6 +54,7 @@
#define LP_NEW_VERTEX 0x1000
#define LP_NEW_VS 0x2000
#define LP_NEW_QUERY 0x4000
#define LP_NEW_BLEND_COLOR 0x8000
struct vertex_info;
@ -65,11 +66,18 @@ struct lp_fragment_shader;
struct lp_fragment_shader_variant_key
{
enum pipe_format zsbuf_format;
struct pipe_depth_state depth;
struct pipe_alpha_state alpha;
struct pipe_blend_state blend;
enum pipe_format zsbuf_format;
unsigned nr_cbufs:8;
unsigned flatshade:1;
unsigned scissor:1;
struct {
ubyte colormask;
} cbuf_blend[PIPE_MAX_COLOR_BUFS];
struct lp_sampler_static_state sampler[PIPE_MAX_SAMPLERS];
};
@ -80,9 +88,9 @@ struct lp_fragment_shader_variant
struct lp_fragment_shader_variant_key key;
LLVMValueRef function;
LLVMValueRef function[2];
lp_jit_frag_func jit_function;
lp_jit_frag_func jit_function[2];
struct lp_fragment_shader_variant *next;
};
@ -211,12 +219,6 @@ llvmpipe_draw_range_elements(struct pipe_context *pipe,
unsigned max_index,
unsigned mode, unsigned start, unsigned count);
void
llvmpipe_map_transfers(struct llvmpipe_context *lp);
void
llvmpipe_unmap_transfers(struct llvmpipe_context *lp);
void
llvmpipe_map_texture_surfaces(struct llvmpipe_context *lp);
@ -224,11 +226,4 @@ void
llvmpipe_unmap_texture_surfaces(struct llvmpipe_context *lp);
struct vertex_info *
llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe);
struct vertex_info *
llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe);
#endif

View file

@ -73,7 +73,9 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
const struct pipe_blend_color *blend_color )
{
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
unsigned i, j;
if(!blend_color)
return;
if(memcmp(&llvmpipe->blend_color, blend_color, sizeof *blend_color) == 0)
return;
@ -82,13 +84,7 @@ void llvmpipe_set_blend_color( struct pipe_context *pipe,
memcpy(&llvmpipe->blend_color, blend_color, sizeof *blend_color);
if(!llvmpipe->jit_context.blend_color)
llvmpipe->jit_context.blend_color = align_malloc(4 * 16, 16);
for (i = 0; i < 4; ++i) {
uint8_t c = float_to_ubyte(blend_color->color[i]);
for (j = 0; j < 16; ++j)
llvmpipe->jit_context.blend_color[i*16 + j] = c;
}
llvmpipe->dirty |= LP_NEW_BLEND_COLOR;
}
@ -117,9 +113,6 @@ llvmpipe_bind_depth_stencil_state(struct pipe_context *pipe,
llvmpipe->depth_stencil = depth_stencil;
if(llvmpipe->depth_stencil)
llvmpipe->jit_context.alpha_ref_value = llvmpipe->depth_stencil->alpha.ref_value;
llvmpipe->dirty |= LP_NEW_DEPTH_STENCIL_ALPHA;
}

View file

@ -33,165 +33,113 @@
#include "draw/draw_private.h"
#include "lp_context.h"
#include "lp_screen.h"
#include "lp_setup.h"
#include "lp_state.h"
/**
* Mark the current vertex layout as "invalid".
* We'll validate the vertex layout later, when we start to actually
* render a point or line or tri.
*/
static void
invalidate_vertex_layout(struct llvmpipe_context *llvmpipe)
{
llvmpipe->vertex_info.num_attribs = 0;
}
/**
* The vertex info describes how to convert the post-transformed vertices
* (simple float[][4]) used by the 'draw' module into vertices for
* rasterization.
*
* This function validates the vertex layout and returns a pointer to a
* vertex_info object.
*/
struct vertex_info *
llvmpipe_get_vertex_info(struct llvmpipe_context *llvmpipe)
{
struct vertex_info *vinfo = &llvmpipe->vertex_info;
if (vinfo->num_attribs == 0) {
/* compute vertex layout now */
const struct lp_fragment_shader *lpfs = llvmpipe->fs;
struct vertex_info *vinfo_vbuf = &llvmpipe->vertex_info_vbuf;
const uint num = draw_num_shader_outputs(llvmpipe->draw);
uint i;
/* Tell draw_vbuf to simply emit the whole post-xform vertex
* as-is. No longer any need to try and emit draw vertex_header
* info.
*/
vinfo_vbuf->num_attribs = 0;
for (i = 0; i < num; i++) {
draw_emit_vertex_attr(vinfo_vbuf, EMIT_4F, INTERP_PERSPECTIVE, i);
}
draw_compute_vertex_size(vinfo_vbuf);
/*
* Loop over fragment shader inputs, searching for the matching output
* from the vertex shader.
*/
vinfo->num_attribs = 0;
for (i = 0; i < lpfs->info.num_inputs; i++) {
int src;
enum interp_mode interp;
switch (lpfs->info.input_interpolate[i]) {
case TGSI_INTERPOLATE_CONSTANT:
interp = INTERP_CONSTANT;
break;
case TGSI_INTERPOLATE_LINEAR:
interp = INTERP_LINEAR;
break;
case TGSI_INTERPOLATE_PERSPECTIVE:
interp = INTERP_PERSPECTIVE;
break;
default:
assert(0);
interp = INTERP_LINEAR;
}
switch (lpfs->info.input_semantic_name[i]) {
case TGSI_SEMANTIC_POSITION:
interp = INTERP_POS;
break;
case TGSI_SEMANTIC_COLOR:
if (llvmpipe->rasterizer->flatshade) {
interp = INTERP_CONSTANT;
}
break;
}
/* this includes texcoords and varying vars */
src = draw_find_shader_output(llvmpipe->draw,
lpfs->info.input_semantic_name[i],
lpfs->info.input_semantic_index[i]);
draw_emit_vertex_attr(vinfo, EMIT_4F, interp, src);
}
llvmpipe->psize_slot = draw_find_shader_output(llvmpipe->draw,
TGSI_SEMANTIC_PSIZE, 0);
if (llvmpipe->psize_slot > 0) {
draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
llvmpipe->psize_slot);
}
draw_compute_vertex_size(vinfo);
}
return vinfo;
}
/**
* Called from vbuf module.
*
* Note that there's actually two different vertex layouts in llvmpipe.
*
* The normal one is computed in llvmpipe_get_vertex_info() above and is
* used by the point/line/tri "setup" code.
*
* The other one (this one) is only used by the vbuf module (which is
* not normally used by default but used in testing). For the vbuf module,
* we basically want to pass-through the draw module's vertex layout as-is.
* When the llvmpipe vbuf code begins drawing, the normal vertex layout
* will come into play again.
*/
struct vertex_info *
llvmpipe_get_vbuf_vertex_info(struct llvmpipe_context *llvmpipe)
{
(void) llvmpipe_get_vertex_info(llvmpipe);
return &llvmpipe->vertex_info_vbuf;
}
/**
* Recompute cliprect from scissor bounds, scissor enable and surface size.
* This function validates the vertex layout.
*/
static void
compute_cliprect(struct llvmpipe_context *lp)
compute_vertex_info(struct llvmpipe_context *llvmpipe)
{
/* LP_NEW_FRAMEBUFFER
*/
uint surfWidth = lp->framebuffer.width;
uint surfHeight = lp->framebuffer.height;
const struct lp_fragment_shader *lpfs = llvmpipe->fs;
struct vertex_info *vinfo = &llvmpipe->vertex_info;
const uint num = draw_num_shader_outputs(llvmpipe->draw);
uint i;
/* LP_NEW_RASTERIZER
/* Tell setup to tell the draw module to simply emit the whole
* post-xform vertex as-is.
*
* Not really sure if this is the best approach.
*/
if (lp->rasterizer->scissor) {
/* LP_NEW_SCISSOR
*
* clip to scissor rect:
*/
lp->cliprect.minx = MAX2(lp->scissor.minx, 0);
lp->cliprect.miny = MAX2(lp->scissor.miny, 0);
lp->cliprect.maxx = MIN2(lp->scissor.maxx, surfWidth);
lp->cliprect.maxy = MIN2(lp->scissor.maxy, surfHeight);
vinfo->num_attribs = 0;
for (i = 0; i < num; i++) {
draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, i);
}
else {
/* clip to surface bounds */
lp->cliprect.minx = 0;
lp->cliprect.miny = 0;
lp->cliprect.maxx = surfWidth;
lp->cliprect.maxy = surfHeight;
draw_compute_vertex_size(vinfo);
lp_setup_set_vertex_info(llvmpipe->setup, vinfo);
/*
llvmpipe->psize_slot = draw_find_vs_output(llvmpipe->draw,
TGSI_SEMANTIC_PSIZE, 0);
*/
/* Now match FS inputs against emitted vertex data. It's also
* entirely possible to just have a fixed layout for FS input,
* determined by the fragment shader itself, and adjust the draw
* outputs to match that.
*/
{
struct lp_shader_input inputs[PIPE_MAX_SHADER_INPUTS];
for (i = 0; i < lpfs->info.num_inputs; i++) {
/* This can be precomputed, except for flatshade:
*/
switch (lpfs->info.input_semantic_name[i]) {
case TGSI_SEMANTIC_FACE:
inputs[i].interp = LP_INTERP_FACING;
break;
case TGSI_SEMANTIC_POSITION:
inputs[i].interp = LP_INTERP_POSITION;
break;
case TGSI_SEMANTIC_COLOR:
/* Colors are linearly interpolated in the fragment shader
* even when flatshading is active. This just tells the
* setup module to use coefficients with ddx==0 and
* ddy==0.
*/
if (llvmpipe->rasterizer->flatshade)
inputs[i].interp = LP_INTERP_CONSTANT;
else
inputs[i].interp = LP_INTERP_LINEAR;
break;
default:
switch (lpfs->info.input_interpolate[i]) {
case TGSI_INTERPOLATE_CONSTANT:
inputs[i].interp = LP_INTERP_CONSTANT;
break;
case TGSI_INTERPOLATE_LINEAR:
inputs[i].interp = LP_INTERP_LINEAR;
break;
case TGSI_INTERPOLATE_PERSPECTIVE:
inputs[i].interp = LP_INTERP_PERSPECTIVE;
break;
default:
assert(0);
break;
}
}
/* Search for each input in current vs output:
*/
inputs[i].src_index =
draw_find_shader_output(llvmpipe->draw,
lpfs->info.input_semantic_name[i],
lpfs->info.input_semantic_index[i]);
}
lp_setup_set_fs_inputs(llvmpipe->setup,
inputs,
lpfs->info.num_inputs);
}
}
/* Hopefully this will remain quite simple, otherwise need to pull in
/**
* Handle state changes.
* Called just prior to drawing anything (pipe::draw_arrays(), etc).
*
* Hopefully this will remain quite simple, otherwise need to pull in
* something like the state tracker mechanism.
*/
void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
@ -205,28 +153,40 @@ void llvmpipe_update_derived( struct llvmpipe_context *llvmpipe )
llvmpipe->dirty |= LP_NEW_TEXTURE;
}
if (llvmpipe->dirty & (LP_NEW_SAMPLER |
LP_NEW_TEXTURE)) {
/* TODO */
}
if (llvmpipe->dirty & (LP_NEW_RASTERIZER |
LP_NEW_FS |
LP_NEW_VS))
invalidate_vertex_layout( llvmpipe );
if (llvmpipe->dirty & (LP_NEW_SCISSOR |
LP_NEW_RASTERIZER |
LP_NEW_FRAMEBUFFER))
compute_cliprect(llvmpipe);
compute_vertex_info( llvmpipe );
if (llvmpipe->dirty & (LP_NEW_FS |
LP_NEW_BLEND |
LP_NEW_SCISSOR |
LP_NEW_DEPTH_STENCIL_ALPHA |
LP_NEW_RASTERIZER |
LP_NEW_SAMPLER |
LP_NEW_TEXTURE))
llvmpipe_update_fs( llvmpipe );
if (llvmpipe->dirty & LP_NEW_BLEND_COLOR)
lp_setup_set_blend_color(llvmpipe->setup,
&llvmpipe->blend_color);
if (llvmpipe->dirty & LP_NEW_SCISSOR)
lp_setup_set_scissor(llvmpipe->setup, &llvmpipe->scissor);
if (llvmpipe->dirty & LP_NEW_DEPTH_STENCIL_ALPHA)
lp_setup_set_alpha_ref_value(llvmpipe->setup,
llvmpipe->depth_stencil->alpha.ref_value);
if (llvmpipe->dirty & LP_NEW_CONSTANTS)
lp_setup_set_fs_constants(llvmpipe->setup,
llvmpipe->constants[PIPE_SHADER_FRAGMENT]);
if (llvmpipe->dirty & LP_NEW_TEXTURE)
lp_setup_set_sampler_textures(llvmpipe->setup,
llvmpipe->num_textures,
llvmpipe->texture);
llvmpipe->dirty = 0;
}

View file

@ -31,6 +31,8 @@
* Code generate the whole fragment pipeline.
*
* The fragment pipeline consists of the following stages:
* - triangle edge in/out testing
* - scissor test
* - stipple (TBI)
* - early depth test
* - fragment shader
@ -58,11 +60,13 @@
* @author Jose Fonseca <jfonseca@vmware.com>
*/
#include <limits.h>
#include "pipe/p_defines.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_format.h"
#include "util/u_debug_dump.h"
#include "util/u_time.h"
#include "pipe/p_shader_tokens.h"
#include "draw/draw_context.h"
#include "tgsi/tgsi_dump.h"
@ -81,12 +85,14 @@
#include "lp_bld_swizzle.h"
#include "lp_bld_flow.h"
#include "lp_bld_debug.h"
#include "lp_screen.h"
#include "lp_context.h"
#include "lp_buffer.h"
#include "lp_context.h"
#include "lp_debug.h"
#include "lp_perf.h"
#include "lp_screen.h"
#include "lp_setup.h"
#include "lp_state.h"
#include "lp_tex_sample.h"
#include "lp_debug.h"
static const unsigned char quad_offset_x[4] = {0, 1, 0, 1};
@ -185,8 +191,188 @@ generate_depth(LLVMBuilderRef builder,
}
/**
* Generate the code to do inside/outside triangle testing for the
* four pixels in a 2x2 quad. This will set the four elements of the
* quad mask vector to 0 or ~0.
* \param i which quad of the quad group to test, in [0,3]
*/
static void
generate_tri_edge_mask(LLVMBuilderRef builder,
unsigned i,
LLVMValueRef *mask, /* ivec4, out */
LLVMValueRef c0, /* int32 */
LLVMValueRef c1, /* int32 */
LLVMValueRef c2, /* int32 */
LLVMValueRef step0_ptr, /* ivec4 */
LLVMValueRef step1_ptr, /* ivec4 */
LLVMValueRef step2_ptr) /* ivec4 */
{
#define OPTIMIZE_IN_OUT_TEST 0
#if OPTIMIZE_IN_OUT_TEST
struct lp_build_if_state ifctx;
LLVMValueRef not_draw_all;
#endif
struct lp_build_flow_context *flow;
struct lp_type i32_type;
LLVMTypeRef i32vec4_type, mask_type;
LLVMValueRef c0_vec, c1_vec, c2_vec;
LLVMValueRef in_out_mask;
assert(i < 4);
/* int32 vector type */
memset(&i32_type, 0, sizeof i32_type);
i32_type.floating = FALSE; /* values are integers */
i32_type.sign = TRUE; /* values are signed */
i32_type.norm = FALSE; /* values are not normalized */
i32_type.width = 32; /* 32-bit int values */
i32_type.length = 4; /* 4 elements per vector */
i32vec4_type = lp_build_int32_vec4_type();
mask_type = LLVMIntType(32 * 4);
/*
* Use a conditional here to do detailed pixel in/out testing.
* We only have to do this if c0 != INT_MIN.
*/
flow = lp_build_flow_create(builder);
lp_build_flow_scope_begin(flow);
{
#if OPTIMIZE_IN_OUT_TEST
/* not_draw_all = (c0 != INT_MIN) */
not_draw_all = LLVMBuildICmp(builder,
LLVMIntNE,
c0,
LLVMConstInt(LLVMInt32Type(), INT_MIN, 0),
"");
in_out_mask = lp_build_int_const_scalar(i32_type, ~0);
lp_build_flow_scope_declare(flow, &in_out_mask);
/* if (not_draw_all) {... */
lp_build_if(&ifctx, flow, builder, not_draw_all);
#endif
{
LLVMValueRef step0_vec, step1_vec, step2_vec;
LLVMValueRef m0_vec, m1_vec, m2_vec;
LLVMValueRef index, m;
/* c0_vec = {c0, c0, c0, c0}
* Note that we emit this code four times but LLVM optimizes away
* three instances of it.
*/
c0_vec = lp_build_broadcast(builder, i32vec4_type, c0);
c1_vec = lp_build_broadcast(builder, i32vec4_type, c1);
c2_vec = lp_build_broadcast(builder, i32vec4_type, c2);
lp_build_name(c0_vec, "edgeconst0vec");
lp_build_name(c1_vec, "edgeconst1vec");
lp_build_name(c2_vec, "edgeconst2vec");
/* load step0vec, step1, step2 vec from memory */
index = LLVMConstInt(LLVMInt32Type(), i, 0);
step0_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step0_ptr, &index, 1, ""), "");
step1_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step1_ptr, &index, 1, ""), "");
step2_vec = LLVMBuildLoad(builder, LLVMBuildGEP(builder, step2_ptr, &index, 1, ""), "");
lp_build_name(step0_vec, "step0vec");
lp_build_name(step1_vec, "step1vec");
lp_build_name(step2_vec, "step2vec");
/* m0_vec = step0_ptr[i] > c0_vec */
m0_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step0_vec, c0_vec);
m1_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step1_vec, c1_vec);
m2_vec = lp_build_compare(builder, i32_type, PIPE_FUNC_GREATER, step2_vec, c2_vec);
/* in_out_mask = m0_vec & m1_vec & m2_vec */
m = LLVMBuildAnd(builder, m0_vec, m1_vec, "");
in_out_mask = LLVMBuildAnd(builder, m, m2_vec, "");
lp_build_name(in_out_mask, "inoutmaskvec");
}
#if OPTIMIZE_IN_OUT_TEST
lp_build_endif(&ifctx);
#endif
}
lp_build_flow_scope_end(flow);
lp_build_flow_destroy(flow);
/* This is the initial alive/dead pixel mask for a quad of four pixels.
* It's an int[4] vector with each word set to 0 or ~0.
* Words will get cleared when pixels faile the Z test, etc.
*/
*mask = in_out_mask;
}
static LLVMValueRef
generate_scissor_test(LLVMBuilderRef builder,
LLVMValueRef context_ptr,
const struct lp_build_interp_soa_context *interp,
struct lp_type type)
{
LLVMTypeRef vec_type = lp_build_vec_type(type);
LLVMValueRef xpos = interp->pos[0], ypos = interp->pos[1];
LLVMValueRef xmin, ymin, xmax, ymax;
LLVMValueRef m0, m1, m2, m3, m;
/* xpos, ypos contain the window coords for the four pixels in the quad */
assert(xpos);
assert(ypos);
/* get the current scissor bounds, convert to vectors */
xmin = lp_jit_context_scissor_xmin_value(builder, context_ptr);
xmin = lp_build_broadcast(builder, vec_type, xmin);
ymin = lp_jit_context_scissor_ymin_value(builder, context_ptr);
ymin = lp_build_broadcast(builder, vec_type, ymin);
xmax = lp_jit_context_scissor_xmax_value(builder, context_ptr);
xmax = lp_build_broadcast(builder, vec_type, xmax);
ymax = lp_jit_context_scissor_ymax_value(builder, context_ptr);
ymax = lp_build_broadcast(builder, vec_type, ymax);
/* compare the fragment's position coordinates against the scissor bounds */
m0 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, xpos, xmin);
m1 = lp_build_compare(builder, type, PIPE_FUNC_GEQUAL, ypos, ymin);
m2 = lp_build_compare(builder, type, PIPE_FUNC_LESS, xpos, xmax);
m3 = lp_build_compare(builder, type, PIPE_FUNC_LESS, ypos, ymax);
/* AND all the masks together */
m = LLVMBuildAnd(builder, m0, m1, "");
m = LLVMBuildAnd(builder, m, m2, "");
m = LLVMBuildAnd(builder, m, m3, "");
lp_build_name(m, "scissormask");
return m;
}
static LLVMValueRef
build_int32_vec_const(int value)
{
struct lp_type i32_type;
memset(&i32_type, 0, sizeof i32_type);
i32_type.floating = FALSE; /* values are integers */
i32_type.sign = TRUE; /* values are signed */
i32_type.norm = FALSE; /* values are not normalized */
i32_type.width = 32; /* 32-bit int values */
i32_type.length = 4; /* 4 elements per vector */
return lp_build_int_const_scalar(i32_type, value);
}
/**
* Generate the fragment shader, depth/stencil test, and alpha tests.
* \param i which quad in the tile, in range [0,3]
* \param do_tri_test if 1, do triangle edge in/out testing
*/
static void
generate_fs(struct llvmpipe_context *lp,
@ -199,8 +385,15 @@ generate_fs(struct llvmpipe_context *lp,
const struct lp_build_interp_soa_context *interp,
struct lp_build_sampler_soa *sampler,
LLVMValueRef *pmask,
LLVMValueRef *color,
LLVMValueRef depth_ptr)
LLVMValueRef (*color)[4],
LLVMValueRef depth_ptr,
unsigned do_tri_test,
LLVMValueRef c0,
LLVMValueRef c1,
LLVMValueRef c2,
LLVMValueRef step0_ptr,
LLVMValueRef step1_ptr,
LLVMValueRef step2_ptr)
{
const struct tgsi_token *tokens = shader->base.tokens;
LLVMTypeRef elem_type;
@ -214,6 +407,9 @@ generate_fs(struct llvmpipe_context *lp,
boolean early_depth_test;
unsigned attrib;
unsigned chan;
unsigned cbuf;
assert(i < 4);
elem_type = lp_build_elem_type(type);
vec_type = lp_build_vec_type(type);
@ -228,14 +424,32 @@ generate_fs(struct llvmpipe_context *lp,
lp_build_flow_scope_begin(flow);
/* Declare the color and z variables */
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
color[chan] = LLVMGetUndef(vec_type);
lp_build_flow_scope_declare(flow, &color[chan]);
for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
color[cbuf][chan] = LLVMGetUndef(vec_type);
lp_build_flow_scope_declare(flow, &color[cbuf][chan]);
}
}
lp_build_flow_scope_declare(flow, &z);
/* do triangle edge testing */
if (do_tri_test) {
generate_tri_edge_mask(builder, i, pmask,
c0, c1, c2, step0_ptr, step1_ptr, step2_ptr);
}
else {
*pmask = build_int32_vec_const(~0);
}
/* 'mask' will control execution based on quad's pixel alive/killed state */
lp_build_mask_begin(&mask, flow, type, *pmask);
if (key->scissor) {
LLVMValueRef smask =
generate_scissor_test(builder, context_ptr, interp, type);
lp_build_mask_update(&mask, smask);
}
early_depth_test =
key->depth.enabled &&
!key->alpha.enabled &&
@ -265,6 +479,7 @@ generate_fs(struct llvmpipe_context *lp,
/* Alpha test */
/* XXX: should the alpha reference value be passed separately? */
/* XXX: should only test the final assignment to alpha */
if(cbuf == 0 && chan == 3) {
LLVMValueRef alpha = outputs[attrib][chan];
LLVMValueRef alpha_ref_value;
@ -274,9 +489,7 @@ generate_fs(struct llvmpipe_context *lp,
&mask, alpha, alpha_ref_value);
}
if(cbuf == 0)
color[chan] = outputs[attrib][chan];
color[cbuf][chan] = outputs[attrib][chan];
break;
}
@ -331,6 +544,8 @@ generate_blend(const struct pipe_blend_state *blend,
lp_build_context_init(&bld, builder, type);
flow = lp_build_flow_create(builder);
/* we'll use this mask context to skip blending if all pixels are dead */
lp_build_mask_begin(&mask_ctx, flow, type, mask);
vec_type = lp_build_vec_type(type);
@ -368,14 +583,18 @@ generate_blend(const struct pipe_blend_state *blend,
/**
* Generate the runtime callable function for the whole fragment pipeline.
* Note that the function which we generate operates on a block of 16
* pixels at at time. The block contains 2x2 quads. Each quad contains
* 2x2 pixels.
*/
static struct lp_fragment_shader_variant *
static void
generate_fragment(struct llvmpipe_context *lp,
struct lp_fragment_shader *shader,
const struct lp_fragment_shader_variant_key *key)
struct lp_fragment_shader_variant *variant,
unsigned do_tri_test)
{
struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen);
struct lp_fragment_shader_variant *variant;
const struct lp_fragment_shader_variant_key *key = &variant->key;
struct lp_type fs_type;
struct lp_type blend_type;
LLVMTypeRef fs_elem_type;
@ -383,17 +602,18 @@ generate_fragment(struct llvmpipe_context *lp,
LLVMTypeRef fs_int_vec_type;
LLVMTypeRef blend_vec_type;
LLVMTypeRef blend_int_vec_type;
LLVMTypeRef arg_types[9];
LLVMTypeRef arg_types[14];
LLVMTypeRef func_type;
LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type();
LLVMValueRef context_ptr;
LLVMValueRef x;
LLVMValueRef y;
LLVMValueRef a0_ptr;
LLVMValueRef dadx_ptr;
LLVMValueRef dady_ptr;
LLVMValueRef mask_ptr;
LLVMValueRef color_ptr;
LLVMValueRef color_ptr_ptr;
LLVMValueRef depth_ptr;
LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr;
LLVMBasicBlockRef block;
LLVMBuilderRef builder;
LLVMValueRef x0;
@ -401,14 +621,243 @@ generate_fragment(struct llvmpipe_context *lp,
struct lp_build_sampler_soa *sampler;
struct lp_build_interp_soa_context interp;
LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH];
LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH];
LLVMValueRef blend_mask;
LLVMValueRef blend_in_color[NUM_CHANNELS];
LLVMValueRef function;
unsigned num_fs;
unsigned i;
unsigned chan;
unsigned cbuf;
/* TODO: actually pick these based on the fs and color buffer
* characteristics. */
memset(&fs_type, 0, sizeof fs_type);
fs_type.floating = TRUE; /* floating point values */
fs_type.sign = TRUE; /* values are signed */
fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */
fs_type.width = 32; /* 32-bit float */
fs_type.length = 4; /* 4 elements per vector */
num_fs = 4; /* number of quads per block */
memset(&blend_type, 0, sizeof blend_type);
blend_type.floating = FALSE; /* values are integers */
blend_type.sign = FALSE; /* values are unsigned */
blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */
blend_type.width = 8; /* 8-bit ubyte values */
blend_type.length = 16; /* 16 elements per vector */
/*
* Generate the function prototype. Any change here must be reflected in
* lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
*/
fs_elem_type = lp_build_elem_type(fs_type);
fs_vec_type = lp_build_vec_type(fs_type);
fs_int_vec_type = lp_build_int_vec_type(fs_type);
blend_vec_type = lp_build_vec_type(blend_type);
blend_int_vec_type = lp_build_int_vec_type(blend_type);
arg_types[0] = screen->context_ptr_type; /* context */
arg_types[1] = LLVMInt32Type(); /* x */
arg_types[2] = LLVMInt32Type(); /* y */
arg_types[3] = LLVMPointerType(fs_elem_type, 0); /* a0 */
arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* dadx */
arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dady */
arg_types[6] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0); /* color */
arg_types[7] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
arg_types[8] = LLVMInt32Type(); /* c0 */
arg_types[9] = LLVMInt32Type(); /* c1 */
arg_types[10] = LLVMInt32Type(); /* c2 */
/* Note: the step arrays are built as int32[16] but we interpret
* them here as int32_vec4[4].
*/
arg_types[11] = LLVMPointerType(int32_vec4_type, 0);/* step0 */
arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step1 */
arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step2 */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
function = LLVMAddFunction(screen->module, "shader", func_type);
LLVMSetFunctionCallConv(function, LLVMCCallConv);
variant->function[do_tri_test] = function;
/* XXX: need to propagate noalias down into color param now we are
* passing a pointer-to-pointer?
*/
for(i = 0; i < Elements(arg_types); ++i)
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute);
context_ptr = LLVMGetParam(function, 0);
x = LLVMGetParam(function, 1);
y = LLVMGetParam(function, 2);
a0_ptr = LLVMGetParam(function, 3);
dadx_ptr = LLVMGetParam(function, 4);
dady_ptr = LLVMGetParam(function, 5);
color_ptr_ptr = LLVMGetParam(function, 6);
depth_ptr = LLVMGetParam(function, 7);
c0 = LLVMGetParam(function, 8);
c1 = LLVMGetParam(function, 9);
c2 = LLVMGetParam(function, 10);
step0_ptr = LLVMGetParam(function, 11);
step1_ptr = LLVMGetParam(function, 12);
step2_ptr = LLVMGetParam(function, 13);
lp_build_name(context_ptr, "context");
lp_build_name(x, "x");
lp_build_name(y, "y");
lp_build_name(a0_ptr, "a0");
lp_build_name(dadx_ptr, "dadx");
lp_build_name(dady_ptr, "dady");
lp_build_name(color_ptr_ptr, "color_ptr");
lp_build_name(depth_ptr, "depth");
lp_build_name(c0, "c0");
lp_build_name(c1, "c1");
lp_build_name(c2, "c2");
lp_build_name(step0_ptr, "step0");
lp_build_name(step1_ptr, "step1");
lp_build_name(step2_ptr, "step2");
/*
* Function body
*/
block = LLVMAppendBasicBlock(function, "entry");
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, block);
generate_pos0(builder, x, y, &x0, &y0);
lp_build_interp_soa_init(&interp,
shader->base.tokens,
key->flatshade,
builder, fs_type,
a0_ptr, dadx_ptr, dady_ptr,
x0, y0);
/* code generated texture sampling */
sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
/* loop over quads in the block */
for(i = 0; i < num_fs; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
LLVMValueRef out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS];
LLVMValueRef depth_ptr_i;
int cbuf;
if(i != 0)
lp_build_interp_soa_update(&interp, i);
depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");
generate_fs(lp, shader, key,
builder,
fs_type,
context_ptr,
i,
&interp,
sampler,
&fs_mask[i], /* output */
out_color,
depth_ptr_i,
do_tri_test,
c0, c1, c2,
step0_ptr, step1_ptr, step2_ptr);
for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++)
for(chan = 0; chan < NUM_CHANNELS; ++chan)
fs_out_color[cbuf][chan][i] = out_color[cbuf][chan];
}
sampler->destroy(sampler);
/* Loop over color outputs / color buffers to do blending.
*/
for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) {
LLVMValueRef color_ptr;
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0);
/*
* Convert the fs's output color and mask to fit to the blending type.
*/
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
lp_build_conv(builder, fs_type, blend_type,
fs_out_color[cbuf][chan], num_fs,
&blend_in_color[chan], 1);
lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]);
}
lp_build_conv_mask(builder, fs_type, blend_type,
fs_mask, num_fs,
&blend_mask, 1);
color_ptr = LLVMBuildLoad(builder,
LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""),
"");
lp_build_name(color_ptr, "color_ptr%d", cbuf);
/*
* Blending.
*/
generate_blend(&key->blend,
builder,
blend_type,
context_ptr,
blend_mask,
blend_in_color,
color_ptr);
}
LLVMBuildRetVoid(builder);
LLVMDisposeBuilder(builder);
/* Verify the LLVM IR. If invalid, dump and abort */
#ifdef DEBUG
if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) {
if (1)
LLVMDumpValue(function);
abort();
}
#endif
/* Apply optimizations to LLVM IR */
if (1)
LLVMRunFunctionPassManager(screen->pass, function);
if (LP_DEBUG & DEBUG_JIT) {
/* Print the LLVM IR to stderr */
LLVMDumpValue(function);
debug_printf("\n");
}
/*
* Translate the LLVM IR into machine code.
*/
variant->jit_function[do_tri_test] = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, function);
if (LP_DEBUG & DEBUG_ASM)
lp_disassemble(variant->jit_function[do_tri_test]);
}
static struct lp_fragment_shader_variant *
generate_variant(struct llvmpipe_context *lp,
struct lp_fragment_shader *shader,
const struct lp_fragment_shader_variant_key *key)
{
struct lp_fragment_shader_variant *variant;
if (LP_DEBUG & DEBUG_JIT) {
unsigned i;
tgsi_dump(shader->base.tokens, 0);
if(key->depth.enabled) {
debug_printf("depth.format = %s\n", pf_name(key->zsbuf_format));
@ -467,174 +916,10 @@ generate_fragment(struct llvmpipe_context *lp,
variant->shader = shader;
memcpy(&variant->key, key, sizeof *key);
/* TODO: actually pick these based on the fs and color buffer
* characteristics. */
memset(&fs_type, 0, sizeof fs_type);
fs_type.floating = TRUE; /* floating point values */
fs_type.sign = TRUE; /* values are signed */
fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */
fs_type.width = 32; /* 32-bit float */
fs_type.length = 4; /* 4 element per vector */
num_fs = 4;
memset(&blend_type, 0, sizeof blend_type);
blend_type.floating = FALSE; /* values are integers */
blend_type.sign = FALSE; /* values are unsigned */
blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */
blend_type.width = 8; /* 8-bit ubyte values */
blend_type.length = 16; /* 16 elements per vector */
/*
* Generate the function prototype. Any change here must be reflected in
* lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa.
*/
fs_elem_type = lp_build_elem_type(fs_type);
fs_vec_type = lp_build_vec_type(fs_type);
fs_int_vec_type = lp_build_int_vec_type(fs_type);
blend_vec_type = lp_build_vec_type(blend_type);
blend_int_vec_type = lp_build_int_vec_type(blend_type);
arg_types[0] = screen->context_ptr_type; /* context */
arg_types[1] = LLVMInt32Type(); /* x */
arg_types[2] = LLVMInt32Type(); /* y */
arg_types[3] = LLVMPointerType(fs_elem_type, 0); /* a0 */
arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* dadx */
arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dady */
arg_types[6] = LLVMPointerType(fs_int_vec_type, 0); /* mask */
arg_types[7] = LLVMPointerType(blend_vec_type, 0); /* color */
arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */
func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0);
variant->function = LLVMAddFunction(screen->module, "shader", func_type);
LLVMSetFunctionCallConv(variant->function, LLVMCCallConv);
for(i = 0; i < Elements(arg_types); ++i)
if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind)
LLVMAddAttribute(LLVMGetParam(variant->function, i), LLVMNoAliasAttribute);
context_ptr = LLVMGetParam(variant->function, 0);
x = LLVMGetParam(variant->function, 1);
y = LLVMGetParam(variant->function, 2);
a0_ptr = LLVMGetParam(variant->function, 3);
dadx_ptr = LLVMGetParam(variant->function, 4);
dady_ptr = LLVMGetParam(variant->function, 5);
mask_ptr = LLVMGetParam(variant->function, 6);
color_ptr = LLVMGetParam(variant->function, 7);
depth_ptr = LLVMGetParam(variant->function, 8);
lp_build_name(context_ptr, "context");
lp_build_name(x, "x");
lp_build_name(y, "y");
lp_build_name(a0_ptr, "a0");
lp_build_name(dadx_ptr, "dadx");
lp_build_name(dady_ptr, "dady");
lp_build_name(mask_ptr, "mask");
lp_build_name(color_ptr, "color");
lp_build_name(depth_ptr, "depth");
/*
* Function body
*/
block = LLVMAppendBasicBlock(variant->function, "entry");
builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, block);
generate_pos0(builder, x, y, &x0, &y0);
lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type,
a0_ptr, dadx_ptr, dady_ptr,
x0, y0, 2, 0);
/* code generated texture sampling */
sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr);
for(i = 0; i < num_fs; ++i) {
LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
LLVMValueRef out_color[NUM_CHANNELS];
LLVMValueRef depth_ptr_i;
if(i != 0)
lp_build_interp_soa_update(&interp);
fs_mask[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, mask_ptr, &index, 1, ""), "");
depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, "");
generate_fs(lp, shader, key,
builder,
fs_type,
context_ptr,
i,
&interp,
sampler,
&fs_mask[i],
out_color,
depth_ptr_i);
for(chan = 0; chan < NUM_CHANNELS; ++chan)
fs_out_color[chan][i] = out_color[chan];
}
sampler->destroy(sampler);
/*
* Convert the fs's output color and mask to fit to the blending type.
*/
for(chan = 0; chan < NUM_CHANNELS; ++chan) {
lp_build_conv(builder, fs_type, blend_type,
fs_out_color[chan], num_fs,
&blend_in_color[chan], 1);
lp_build_name(blend_in_color[chan], "color.%c", "rgba"[chan]);
}
lp_build_conv_mask(builder, fs_type, blend_type,
fs_mask, num_fs,
&blend_mask, 1);
/*
* Blending.
*/
generate_blend(&key->blend,
builder,
blend_type,
context_ptr,
blend_mask,
blend_in_color,
color_ptr);
LLVMBuildRetVoid(builder);
LLVMDisposeBuilder(builder);
/*
* Translate the LLVM IR into machine code.
*/
#ifdef DEBUG
if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) {
LLVMDumpValue(variant->function);
assert(0);
}
#endif
LLVMRunFunctionPassManager(screen->pass, variant->function);
if (LP_DEBUG & DEBUG_JIT) {
LLVMDumpValue(variant->function);
debug_printf("\n");
}
variant->jit_function = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, variant->function);
if (LP_DEBUG & DEBUG_ASM)
lp_disassemble(variant->jit_function);
generate_fragment(lp, shader, variant, 0);
generate_fragment(lp, shader, variant, 1);
/* insert new variant into linked list */
variant->next = shader->variants;
shader->variants = variant;
@ -692,11 +977,15 @@ llvmpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
variant = shader->variants;
while(variant) {
struct lp_fragment_shader_variant *next = variant->next;
unsigned i;
if(variant->function) {
if(variant->jit_function)
LLVMFreeMachineCodeForFunction(screen->engine, variant->function);
LLVMDeleteFunction(variant->function);
for (i = 0; i < Elements(variant->function); i++) {
if (variant->function[i]) {
if (variant->jit_function[i])
LLVMFreeMachineCodeForFunction(screen->engine,
variant->function[i]);
LLVMDeleteFunction(variant->function[i]);
}
}
FREE(variant);
@ -722,15 +1011,14 @@ llvmpipe_set_constant_buffer(struct pipe_context *pipe,
assert(shader < PIPE_SHADER_TYPES);
assert(index == 0);
if(llvmpipe->constants[shader] == constants)
return;
draw_flush(llvmpipe->draw);
/* note: reference counting */
pipe_buffer_reference(&llvmpipe->constants[shader], constants);
if(shader == PIPE_SHADER_FRAGMENT) {
llvmpipe->jit_context.constants = data;
}
if(shader == PIPE_SHADER_VERTEX) {
draw_set_mapped_constant_buffer(llvmpipe->draw, PIPE_SHADER_VERTEX, 0,
data, size);
@ -767,21 +1055,30 @@ make_variant_key(struct llvmpipe_context *lp,
key->alpha.func = lp->depth_stencil->alpha.func;
/* alpha.ref_value is passed in jit_context */
if(lp->framebuffer.cbufs[0]) {
key->flatshade = lp->rasterizer->flatshade;
key->scissor = lp->rasterizer->scissor;
if (lp->framebuffer.nr_cbufs) {
memcpy(&key->blend, lp->blend, sizeof key->blend);
}
key->nr_cbufs = lp->framebuffer.nr_cbufs;
for (i = 0; i < lp->framebuffer.nr_cbufs; i++) {
const struct util_format_description *format_desc;
unsigned chan;
memcpy(&key->blend, lp->blend, sizeof key->blend);
format_desc = util_format_description(lp->framebuffer.cbufs[0]->format);
format_desc = util_format_description(lp->framebuffer.cbufs[i]->format);
assert(format_desc->layout == UTIL_FORMAT_COLORSPACE_RGB ||
format_desc->layout == UTIL_FORMAT_COLORSPACE_SRGB);
/* mask out color channels not present in the color buffer */
/* mask out color channels not present in the color buffer.
* Should be simple to incorporate per-cbuf writemasks:
*/
for(chan = 0; chan < 4; ++chan) {
enum util_format_swizzle swizzle = format_desc->swizzle[chan];
if(swizzle > 4)
key->blend.rt[0].colormask &= ~(1 << chan);
if(swizzle <= UTIL_FORMAT_SWIZZLE_W)
key->blend.rt[0].colormask |= (1 << chan);
}
}
@ -791,12 +1088,17 @@ make_variant_key(struct llvmpipe_context *lp,
}
/**
* Update fragment state. This is called just prior to drawing
* something when some fragment-related state has changed.
*/
void
llvmpipe_update_fs(struct llvmpipe_context *lp)
{
struct lp_fragment_shader *shader = lp->fs;
struct lp_fragment_shader_variant_key key;
struct lp_fragment_shader_variant *variant;
boolean opaque;
make_variant_key(lp, shader, &key);
@ -808,8 +1110,34 @@ llvmpipe_update_fs(struct llvmpipe_context *lp)
variant = variant->next;
}
if(!variant)
variant = generate_fragment(lp, shader, &key);
if (!variant) {
struct util_time t0, t1;
int64_t dt;
util_time_get(&t0);
variant = generate_variant(lp, shader, &key);
util_time_get(&t1);
dt = util_time_diff(&t0, &t1);
LP_COUNT_ADD(llvm_compile_time, dt);
LP_COUNT_ADD(nr_llvm_compiles, 2); /* emit vs. omit in/out test */
}
shader->current = variant;
/* TODO: put this in the variant */
/* TODO: most of these can be relaxed, in particular the colormask */
opaque = !key.blend.logicop_enable &&
!key.blend.rt[0].blend_enable &&
key.blend.rt[0].colormask == 0xf &&
!key.alpha.enabled &&
!key.depth.enabled &&
!key.scissor &&
!shader->info.uses_kill
? TRUE : FALSE;
lp_setup_set_fs_functions(lp->setup,
shader->current->jit_function[0],
shader->current->jit_function[1],
opaque);
}

View file

@ -29,6 +29,7 @@
#include "util/u_memory.h"
#include "lp_context.h"
#include "lp_state.h"
#include "lp_setup.h"
#include "draw/draw_context.h"
@ -53,6 +54,17 @@ void llvmpipe_bind_rasterizer_state(struct pipe_context *pipe,
llvmpipe->rasterizer = rasterizer;
/* Note: we can immediately set the triangle state here and
* not worry about binning because we handle culling during
* triangle setup, not when rasterizing the bins.
*/
if (llvmpipe->rasterizer) {
lp_setup_set_triangle_state( llvmpipe->setup,
llvmpipe->rasterizer->cull_mode,
llvmpipe->rasterizer->front_winding == PIPE_WINDING_CCW,
llvmpipe->rasterizer->scissor);
}
llvmpipe->dirty |= LP_NEW_RASTERIZER;
}

View file

@ -38,7 +38,6 @@
#include "lp_context.h"
#include "lp_state.h"
#include "lp_texture.h"
#include "lp_tex_cache.h"
#include "draw/draw_context.h"
@ -126,17 +125,6 @@ llvmpipe_set_sampler_textures(struct pipe_context *pipe,
struct pipe_texture *tex = i < num ? texture[i] : NULL;
pipe_texture_reference(&llvmpipe->texture[i], tex);
lp_tex_tile_cache_set_texture(llvmpipe->tex_cache[i], tex);
if(tex) {
struct llvmpipe_texture *lp_tex = llvmpipe_texture(tex);
struct lp_jit_texture *jit_tex = &llvmpipe->jit_context.textures[i];
jit_tex->width = tex->width0;
jit_tex->height = tex->height0;
jit_tex->stride = lp_tex->stride[0];
if(!lp_tex->dt)
jit_tex->data = lp_tex->data;
}
}
llvmpipe->num_textures = num;
@ -167,7 +155,6 @@ llvmpipe_set_vertex_sampler_textures(struct pipe_context *pipe,
struct pipe_texture *tex = i < num_textures ? textures[i] : NULL;
pipe_texture_reference(&llvmpipe->vertex_textures[i], tex);
lp_tex_tile_cache_set_texture(llvmpipe->vertex_tex_cache[i], tex);
}
llvmpipe->num_vertex_textures = num_textures;

View file

@ -28,11 +28,12 @@
/* Authors: Keith Whitwell <keith@tungstengraphics.com>
*/
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "util/u_surface.h"
#include "lp_context.h"
#include "lp_state.h"
#include "lp_tile_cache.h"
#include "lp_setup.h"
#include "draw/draw_context.h"
@ -40,54 +41,19 @@
/**
* XXX this might get moved someday
* Set the framebuffer surface info: color buffers, zbuffer, stencil buffer.
* Here, we flush the old surfaces and update the tile cache to point to the new
* surfaces.
*/
void
llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
const struct pipe_framebuffer_state *fb)
{
struct llvmpipe_context *lp = llvmpipe_context(pipe);
uint i;
draw_flush(lp->draw);
boolean changed = !util_framebuffer_state_equal(&lp->framebuffer, fb);
for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
/* check if changing cbuf */
if (lp->framebuffer.cbufs[i] != fb->cbufs[i]) {
/* flush old */
lp_tile_cache_map_transfers(lp->cbuf_cache[i]);
lp_flush_tile_cache(lp->cbuf_cache[i]);
if (changed) {
/* assign new */
pipe_surface_reference(&lp->framebuffer.cbufs[i], fb->cbufs[i]);
/* update cache */
lp_tile_cache_set_surface(lp->cbuf_cache[i], fb->cbufs[i]);
}
}
lp->framebuffer.nr_cbufs = fb->nr_cbufs;
/* zbuf changing? */
if (lp->framebuffer.zsbuf != fb->zsbuf) {
if(lp->zsbuf_transfer) {
struct pipe_screen *screen = pipe->screen;
if(lp->zsbuf_map) {
screen->transfer_unmap(screen, lp->zsbuf_transfer);
lp->zsbuf_map = NULL;
}
screen->tex_transfer_destroy(lp->zsbuf_transfer);
lp->zsbuf_transfer = NULL;
}
/* assign new */
pipe_surface_reference(&lp->framebuffer.zsbuf, fb->zsbuf);
util_copy_framebuffer_state(&lp->framebuffer, fb);
/* Tell draw module how deep the Z/depth buffer is */
if (lp->framebuffer.zsbuf) {
@ -104,10 +70,9 @@ llvmpipe_set_framebuffer_state(struct pipe_context *pipe,
}
draw_set_mrd(lp->draw, mrd);
}
lp_setup_bind_framebuffer( lp->setup, &lp->framebuffer );
lp->dirty |= LP_NEW_FRAMEBUFFER;
}
lp->framebuffer.width = fb->width;
lp->framebuffer.height = fb->height;
lp->dirty |= LP_NEW_FRAMEBUFFER;
}

View file

@ -1,303 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Texture tile caching.
*
* Author:
* Brian Paul
*/
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_tile.h"
#include "util/u_format.h"
#include "util/u_math.h"
#include "lp_context.h"
#include "lp_texture.h"
#include "lp_tex_cache.h"
/**
* Return the position in the cache for the tile that contains win pos (x,y).
* We currently use a direct mapped cache so this is like a hack key.
* At some point we should investige something more sophisticated, like
* a LRU replacement policy.
*/
#define CACHE_POS(x, y) \
(((x) + (y) * 5) % NUM_ENTRIES)
/**
* Is the tile at (x,y) in cleared state?
*/
static INLINE uint
is_clear_flag_set(const uint *bitvec, union tex_tile_address addr)
{
int pos, bit;
pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
bit = bitvec[pos / 32] & (1 << (pos & 31));
return bit;
}
/**
* Mark the tile at (x,y) as not cleared.
*/
static INLINE void
clear_clear_flag(uint *bitvec, union tex_tile_address addr)
{
int pos;
pos = addr.bits.y * (MAX_TEX_WIDTH / TEX_TILE_SIZE) + addr.bits.x;
assert(pos / 32 < (MAX_TEX_WIDTH / TEX_TILE_SIZE) * (MAX_TEX_HEIGHT / TEX_TILE_SIZE) / 32);
bitvec[pos / 32] &= ~(1 << (pos & 31));
}
struct llvmpipe_tex_tile_cache *
lp_create_tex_tile_cache( struct pipe_screen *screen )
{
struct llvmpipe_tex_tile_cache *tc;
uint pos;
tc = CALLOC_STRUCT( llvmpipe_tex_tile_cache );
if (tc) {
tc->screen = screen;
for (pos = 0; pos < NUM_ENTRIES; pos++) {
tc->entries[pos].addr.bits.invalid = 1;
}
tc->last_tile = &tc->entries[0]; /* any tile */
}
return tc;
}
void
lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc)
{
struct pipe_screen *screen;
uint pos;
for (pos = 0; pos < NUM_ENTRIES; pos++) {
/*assert(tc->entries[pos].x < 0);*/
}
if (tc->transfer) {
screen = tc->transfer->texture->screen;
screen->tex_transfer_destroy(tc->transfer);
}
if (tc->tex_trans) {
screen = tc->tex_trans->texture->screen;
screen->tex_transfer_destroy(tc->tex_trans);
}
FREE( tc );
}
void
lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc)
{
if (tc->transfer && !tc->transfer_map)
tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
if (tc->tex_trans && !tc->tex_trans_map)
tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
}
void
lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc)
{
if (tc->transfer_map) {
tc->screen->transfer_unmap(tc->screen, tc->transfer);
tc->transfer_map = NULL;
}
if (tc->tex_trans_map) {
tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
tc->tex_trans_map = NULL;
}
}
void
lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc)
{
if (tc->texture) {
struct llvmpipe_texture *lpt = llvmpipe_texture(tc->texture);
if (lpt->timestamp != tc->timestamp) {
/* texture was modified, invalidate all cached tiles */
uint i;
for (i = 0; i < NUM_ENTRIES; i++) {
tc->entries[i].addr.bits.invalid = 1;
}
tc->timestamp = lpt->timestamp;
}
}
}
/**
* Specify the texture to cache.
*/
void
lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
struct pipe_texture *texture)
{
uint i;
assert(!tc->transfer);
if (tc->texture != texture) {
pipe_texture_reference(&tc->texture, texture);
if (tc->tex_trans) {
struct pipe_screen *screen = tc->tex_trans->texture->screen;
if (tc->tex_trans_map) {
screen->transfer_unmap(screen, tc->tex_trans);
tc->tex_trans_map = NULL;
}
screen->tex_transfer_destroy(tc->tex_trans);
tc->tex_trans = NULL;
}
/* mark as entries as invalid/empty */
/* XXX we should try to avoid this when the teximage hasn't changed */
for (i = 0; i < NUM_ENTRIES; i++) {
tc->entries[i].addr.bits.invalid = 1;
}
tc->tex_face = -1; /* any invalid value here */
}
}
/**
* Given the texture face, level, zslice, x and y values, compute
* the cache entry position/index where we'd hope to find the
* cached texture tile.
* This is basically a direct-map cache.
* XXX There's probably lots of ways in which we can improve this.
*/
static INLINE uint
tex_cache_pos( union tex_tile_address addr )
{
uint entry = (addr.bits.x +
addr.bits.y * 9 +
addr.bits.z * 3 +
addr.bits.face +
addr.bits.level * 7);
return entry % NUM_ENTRIES;
}
/**
* Similar to lp_get_cached_tile() but for textures.
* Tiles are read-only and indexed with more params.
*/
const struct llvmpipe_cached_tex_tile *
lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
union tex_tile_address addr )
{
struct pipe_screen *screen = tc->screen;
struct llvmpipe_cached_tex_tile *tile;
tile = tc->entries + tex_cache_pos( addr );
if (addr.value != tile->addr.value) {
/* cache miss. Most misses are because we've invaldiated the
* texture cache previously -- most commonly on binding a new
* texture. Currently we effectively flush the cache on texture
* bind.
*/
#if 0
_debug_printf("miss at %u: x=%d y=%d z=%d face=%d level=%d\n"
" tile %u: x=%d y=%d z=%d face=%d level=%d\n",
pos, x/TEX_TILE_SIZE, y/TEX_TILE_SIZE, z, face, level,
pos, tile->addr.bits.x, tile->addr.bits.y, tile->z, tile->face, tile->level);
#endif
/* check if we need to get a new transfer */
if (!tc->tex_trans ||
tc->tex_face != addr.bits.face ||
tc->tex_level != addr.bits.level ||
tc->tex_z != addr.bits.z) {
/* get new transfer (view into texture) */
if (tc->tex_trans) {
if (tc->tex_trans_map) {
tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
tc->tex_trans_map = NULL;
}
screen->tex_transfer_destroy(tc->tex_trans);
tc->tex_trans = NULL;
}
tc->tex_trans =
screen->get_tex_transfer(screen, tc->texture,
addr.bits.face,
addr.bits.level,
addr.bits.z,
PIPE_TRANSFER_READ, 0, 0,
u_minify(tc->texture->width0, addr.bits.level),
u_minify(tc->texture->height0, addr.bits.level));
tc->tex_trans_map = screen->transfer_map(screen, tc->tex_trans);
tc->tex_face = addr.bits.face;
tc->tex_level = addr.bits.level;
tc->tex_z = addr.bits.z;
}
{
unsigned x = addr.bits.x * TEX_TILE_SIZE;
unsigned y = addr.bits.y * TEX_TILE_SIZE;
unsigned w = TEX_TILE_SIZE;
unsigned h = TEX_TILE_SIZE;
if (pipe_clip_tile(x, y, &w, &h, tc->tex_trans)) {
assert(0);
}
util_format_read_4ub(tc->tex_trans->texture->format,
(uint8_t *)tile->color, sizeof tile->color[0],
tc->tex_trans_map, tc->tex_trans->stride,
x, y, w, h);
}
tile->addr = addr;
}
tc->last_tile = tile;
return tile;
}

View file

@ -1,151 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#ifndef LP_TEX_CACHE_H
#define LP_TEX_CACHE_H
#include "pipe/p_compiler.h"
struct llvmpipe_context;
struct llvmpipe_tex_tile_cache;
/**
* Cache tile size (width and height). This needs to be a power of two.
*/
#define TEX_TILE_SIZE 64
/* If we need to support > 4096, just expand this to be a 64 bit
* union, or consider tiling in Z as well.
*/
union tex_tile_address {
struct {
unsigned x:6; /* 4096 / TEX_TILE_SIZE */
unsigned y:6; /* 4096 / TEX_TILE_SIZE */
unsigned z:12; /* 4096 -- z not tiled */
unsigned face:3;
unsigned level:4;
unsigned invalid:1;
} bits;
unsigned value;
};
struct llvmpipe_cached_tex_tile
{
union tex_tile_address addr;
uint8_t color[TEX_TILE_SIZE][TEX_TILE_SIZE][4];
};
#define NUM_ENTRIES 50
/** XXX move these */
#define MAX_TEX_WIDTH 2048
#define MAX_TEX_HEIGHT 2048
struct llvmpipe_tex_tile_cache
{
struct pipe_screen *screen;
struct pipe_surface *surface; /**< the surface we're caching */
struct pipe_transfer *transfer;
void *transfer_map;
struct pipe_texture *texture; /**< if caching a texture */
unsigned timestamp;
struct llvmpipe_cached_tex_tile entries[NUM_ENTRIES];
struct pipe_transfer *tex_trans;
void *tex_trans_map;
int tex_face, tex_level, tex_z;
struct llvmpipe_cached_tex_tile *last_tile; /**< most recently retrieved tile */
};
extern struct llvmpipe_tex_tile_cache *
lp_create_tex_tile_cache( struct pipe_screen *screen );
extern void
lp_destroy_tex_tile_cache(struct llvmpipe_tex_tile_cache *tc);
extern void
lp_tex_tile_cache_map_transfers(struct llvmpipe_tex_tile_cache *tc);
extern void
lp_tex_tile_cache_unmap_transfers(struct llvmpipe_tex_tile_cache *tc);
extern void
lp_tex_tile_cache_set_texture(struct llvmpipe_tex_tile_cache *tc,
struct pipe_texture *texture);
void
lp_tex_tile_cache_validate_texture(struct llvmpipe_tex_tile_cache *tc);
extern const struct llvmpipe_cached_tex_tile *
lp_find_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
union tex_tile_address addr );
static INLINE union tex_tile_address
tex_tile_address( unsigned x,
unsigned y,
unsigned z,
unsigned face,
unsigned level )
{
union tex_tile_address addr;
addr.value = 0;
addr.bits.x = x / TEX_TILE_SIZE;
addr.bits.y = y / TEX_TILE_SIZE;
addr.bits.z = z;
addr.bits.face = face;
addr.bits.level = level;
return addr;
}
/* Quickly retrieve tile if it matches last lookup.
*/
static INLINE const struct llvmpipe_cached_tex_tile *
lp_get_cached_tex_tile(struct llvmpipe_tex_tile_cache *tc,
union tex_tile_address addr )
{
if (tc->last_tile->addr.value == addr.value)
return tc->last_tile;
return lp_find_cached_tex_tile( tc, addr );
}
#endif /* LP_TEX_CACHE_H */

View file

@ -46,7 +46,7 @@
#include "lp_bld_type.h"
#include "lp_bld_sample.h"
#include "lp_bld_tgsi.h"
#include "lp_state.h"
#include "lp_jit.h"
#include "lp_tex_sample.h"

View file

@ -39,36 +39,36 @@
#include "util/u_memory.h"
#include "lp_context.h"
#include "lp_screen.h"
#include "lp_state.h"
#include "lp_texture.h"
#include "lp_screen.h"
#include "lp_tile_size.h"
#include "lp_winsys.h"
/* Simple, maximally packed layout.
*/
/* Conventional allocation path for non-display textures:
/**
* Conventional allocation path for non-display textures:
* Simple, maximally packed layout.
*/
static boolean
llvmpipe_texture_layout(struct llvmpipe_screen *screen,
struct llvmpipe_texture * lpt)
struct llvmpipe_texture *lpt)
{
struct pipe_texture *pt = &lpt->base;
unsigned level;
unsigned width = pt->width0;
unsigned height = pt->height0;
unsigned depth = pt->depth0;
unsigned buffer_size = 0;
for (level = 0; level <= pt->last_level; level++) {
unsigned nblocksx, nblocksy;
/* Allocate storage for whole quads. This is particularly important
* for depth surfaces, which are currently stored in a swizzled format. */
nblocksx = util_format_get_nblocksx(pt->format, align(width, 2));
nblocksy = util_format_get_nblocksy(pt->format, align(height, 2));
* for depth surfaces, which are currently stored in a swizzled format.
*/
nblocksx = util_format_get_nblocksx(pt->format, align(width, TILE_SIZE));
nblocksy = util_format_get_nblocksy(pt->format, align(height, TILE_SIZE));
lpt->stride[level] = align(nblocksx * util_format_get_blocksize(pt->format), 16);
@ -78,7 +78,7 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) *
lpt->stride[level]);
width = u_minify(width, 1);
width = u_minify(width, 1);
height = u_minify(height, 1);
depth = u_minify(depth, 1);
}
@ -88,16 +88,23 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
return lpt->data != NULL;
}
static boolean
llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
struct llvmpipe_texture * lpt)
struct llvmpipe_texture *lpt)
{
struct llvmpipe_winsys *winsys = screen->winsys;
/* Round up the surface size to a multiple of the tile size to
* avoid tile clipping.
*/
unsigned width = align(lpt->base.width0, TILE_SIZE);
unsigned height = align(lpt->base.height0, TILE_SIZE);
lpt->dt = winsys->displaytarget_create(winsys,
lpt->base.format,
lpt->base.width0,
lpt->base.height0,
width, height,
16,
&lpt->stride[0] );
@ -105,9 +112,6 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
}
static struct pipe_texture *
llvmpipe_texture_create(struct pipe_screen *_screen,
const struct pipe_texture *templat)
@ -124,7 +128,7 @@ llvmpipe_texture_create(struct pipe_screen *_screen,
/* XXX: The xlib state tracker is brain-dead and will request
* PIPE_FORMAT_Z16_UNORM no matter how much we tell it we don't support it.
*/
if(lpt->base.format == PIPE_FORMAT_Z16_UNORM)
if (lpt->base.format == PIPE_FORMAT_Z16_UNORM)
lpt->base.format = PIPE_FORMAT_Z32_UNORM;
if (lpt->base.tex_usage & (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
@ -176,6 +180,7 @@ llvmpipe_texture_blanket(struct pipe_screen * screen,
return &lpt->base;
#else
debug_printf("llvmpipe_texture_blanket() not implemented!");
return NULL;
#endif
}
@ -187,12 +192,15 @@ llvmpipe_texture_destroy(struct pipe_texture *pt)
struct llvmpipe_screen *screen = llvmpipe_screen(pt->screen);
struct llvmpipe_texture *lpt = llvmpipe_texture(pt);
if(lpt->dt) {
if (lpt->dt) {
/* display target */
struct llvmpipe_winsys *winsys = screen->winsys;
winsys->displaytarget_destroy(winsys, lpt->dt);
}
else
else {
/* regular texture */
align_free(lpt->data);
}
FREE(lpt);
}
@ -234,7 +242,7 @@ llvmpipe_get_tex_surface(struct pipe_screen *screen,
if (ps->usage & (PIPE_BUFFER_USAGE_CPU_WRITE |
PIPE_BUFFER_USAGE_GPU_WRITE)) {
/* Mark the surface as dirty. The tile cache will look for this. */
/* Mark the surface as dirty. */
lpt->timestamp++;
llvmpipe_screen(screen)->timestamp++;
}
@ -296,8 +304,8 @@ llvmpipe_get_tex_transfer(struct pipe_screen *screen,
pipe_texture_reference(&pt->texture, texture);
pt->x = x;
pt->y = y;
pt->width = w;
pt->height = h;
pt->width = align(w, TILE_SIZE);
pt->height = align(h, TILE_SIZE);
pt->stride = lptex->stride[level];
pt->usage = usage;
pt->face = face;
@ -354,7 +362,8 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
lpt = llvmpipe_texture(transfer->texture);
format = lpt->base.format;
if(lpt->dt) {
if (lpt->dt) {
/* display target */
struct llvmpipe_winsys *winsys = screen->winsys;
map = winsys->displaytarget_map(winsys, lpt->dt,
@ -362,16 +371,16 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
if (map == NULL)
return NULL;
}
else
else {
/* regular texture */
map = lpt->data;
}
/* May want to different things here depending on read/write nature
* of the map:
*/
if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE))
{
if (transfer->texture && (transfer->usage & PIPE_TRANSFER_WRITE)) {
/* Do something to notify sharing contexts of a texture change.
* In llvmpipe, that would mean flushing the texture cache.
*/
screen->timestamp++;
}
@ -385,28 +394,23 @@ llvmpipe_transfer_map( struct pipe_screen *_screen,
static void
llvmpipe_transfer_unmap(struct pipe_screen *_screen,
llvmpipe_transfer_unmap(struct pipe_screen *screen,
struct pipe_transfer *transfer)
{
struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
struct llvmpipe_screen *lp_screen = llvmpipe_screen(screen);
struct llvmpipe_texture *lpt;
assert(transfer->texture);
lpt = llvmpipe_texture(transfer->texture);
if(lpt->dt) {
struct llvmpipe_winsys *winsys = screen->winsys;
if (lpt->dt) {
/* display target */
struct llvmpipe_winsys *winsys = lp_screen->winsys;
winsys->displaytarget_unmap(winsys, lpt->dt);
}
}
void
llvmpipe_init_texture_funcs(struct llvmpipe_context *lp)
{
}
void
llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen)
{

View file

@ -37,6 +37,7 @@ struct pipe_screen;
struct llvmpipe_context;
struct llvmpipe_displaytarget;
struct llvmpipe_texture
{
struct pipe_texture base;
@ -58,6 +59,7 @@ struct llvmpipe_texture
unsigned timestamp;
};
struct llvmpipe_transfer
{
struct pipe_transfer base;
@ -73,6 +75,14 @@ llvmpipe_texture(struct pipe_texture *pt)
return (struct llvmpipe_texture *) pt;
}
static INLINE const struct llvmpipe_texture *
llvmpipe_texture_const(const struct pipe_texture *pt)
{
return (const struct llvmpipe_texture *) pt;
}
static INLINE struct llvmpipe_transfer *
llvmpipe_transfer(struct pipe_transfer *pt)
{
@ -80,11 +90,8 @@ llvmpipe_transfer(struct pipe_transfer *pt)
}
extern void
llvmpipe_init_texture_funcs( struct llvmpipe_context *llvmpipe );
extern void
llvmpipe_init_screen_texture_funcs(struct pipe_screen *screen);
#endif /* LP_TEXTURE */
#endif /* LP_TEXTURE_H */

View file

@ -1,356 +0,0 @@
/**************************************************************************
*
* Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
* 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
/**
* Texture tile caching.
*
* Author:
* Brian Paul
*/
#include "util/u_inlines.h"
#include "util/u_memory.h"
#include "util/u_math.h"
#include "util/u_tile.h"
#include "util/u_rect.h"
#include "lp_context.h"
#include "lp_tile_soa.h"
#include "lp_tile_cache.h"
#define MAX_WIDTH 4096
#define MAX_HEIGHT 4096
enum llvmpipe_tile_status
{
LP_TILE_STATUS_UNDEFINED = 0,
LP_TILE_STATUS_CLEAR = 1,
LP_TILE_STATUS_DEFINED = 2
};
struct llvmpipe_cached_tile
{
enum llvmpipe_tile_status status;
/** color in SOA format */
uint8_t *color;
};
struct llvmpipe_tile_cache
{
struct pipe_screen *screen;
struct pipe_surface *surface; /**< the surface we're caching */
struct pipe_transfer *transfer;
void *transfer_map;
struct llvmpipe_cached_tile entries[MAX_WIDTH/TILE_SIZE][MAX_HEIGHT/TILE_SIZE];
uint8_t clear_color[4]; /**< for color bufs */
uint clear_val; /**< for z+stencil, or packed color clear value */
struct llvmpipe_cached_tile *last_tile; /**< most recently retrieved tile */
};
struct llvmpipe_tile_cache *
lp_create_tile_cache( struct pipe_screen *screen )
{
struct llvmpipe_tile_cache *tc;
int maxLevels, maxTexSize;
/* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
maxTexSize = 1 << (maxLevels - 1);
assert(MAX_WIDTH >= maxTexSize);
tc = CALLOC_STRUCT( llvmpipe_tile_cache );
if(!tc)
return NULL;
tc->screen = screen;
return tc;
}
void
lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
{
struct pipe_screen *screen;
unsigned x, y;
for (y = 0; y < MAX_HEIGHT; y += TILE_SIZE) {
for (x = 0; x < MAX_WIDTH; x += TILE_SIZE) {
struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
if(tile->color)
align_free(tile->color);
}
}
if (tc->transfer) {
screen = tc->transfer->texture->screen;
screen->tex_transfer_destroy(tc->transfer);
}
FREE( tc );
}
/**
* Specify the surface to cache.
*/
void
lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
struct pipe_surface *ps)
{
if (tc->transfer) {
struct pipe_screen *screen = tc->transfer->texture->screen;
if (ps == tc->surface)
return;
if (tc->transfer_map) {
screen->transfer_unmap(screen, tc->transfer);
tc->transfer_map = NULL;
}
screen->tex_transfer_destroy(tc->transfer);
tc->transfer = NULL;
}
tc->surface = ps;
if (ps) {
struct pipe_screen *screen = ps->texture->screen;
unsigned x, y;
tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
ps->level, ps->zslice,
PIPE_TRANSFER_READ_WRITE,
0, 0, ps->width, ps->height);
for (y = 0; y < ps->height; y += TILE_SIZE) {
for (x = 0; x < ps->width; x += TILE_SIZE) {
struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
tile->status = LP_TILE_STATUS_UNDEFINED;
if(!tile->color)
tile->color = align_malloc( TILE_SIZE*TILE_SIZE*NUM_CHANNELS, 16 );
}
}
}
}
/**
* Return the transfer being cached.
*/
struct pipe_surface *
lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
{
return tc->surface;
}
void
lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
{
if (tc->transfer && !tc->transfer_map)
tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
}
void
lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
{
if (tc->transfer_map) {
tc->screen->transfer_unmap(tc->screen, tc->transfer);
tc->transfer_map = NULL;
}
}
/**
* Set a tile to a solid color.
*/
static void
clear_tile(struct llvmpipe_cached_tile *tile,
uint8_t clear_color[4])
{
if (clear_color[0] == clear_color[1] &&
clear_color[1] == clear_color[2] &&
clear_color[2] == clear_color[3]) {
memset(tile->color, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
}
else {
uint x, y, chan;
for (y = 0; y < TILE_SIZE; y++)
for (x = 0; x < TILE_SIZE; x++)
for (chan = 0; chan < 4; ++chan)
TILE_PIXEL(tile->color, x, y, chan) = clear_color[chan];
}
}
/**
* Flush the tile cache: write all dirty tiles back to the transfer.
* any tiles "flagged" as cleared will be "really" cleared.
*/
void
lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
{
struct pipe_transfer *pt = tc->transfer;
unsigned x, y;
if(!pt)
return;
assert(tc->transfer_map);
/* push the tile to all positions marked as clear */
for (y = 0; y < pt->height; y += TILE_SIZE) {
for (x = 0; x < pt->width; x += TILE_SIZE) {
struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
if(tile->status != LP_TILE_STATUS_UNDEFINED) {
unsigned w = TILE_SIZE;
unsigned h = TILE_SIZE;
if (!pipe_clip_tile(x, y, &w, &h, pt)) {
switch(tile->status) {
case LP_TILE_STATUS_CLEAR:
/* Actually clear the tiles which were flagged as being in a
* clear state. */
util_fill_rect(tc->transfer_map, pt->texture->format, pt->stride,
x, y, w, h,
tc->clear_val);
break;
case LP_TILE_STATUS_DEFINED:
lp_tile_write_4ub(pt->texture->format,
tile->color,
tc->transfer_map, pt->stride,
x, y, w, h);
break;
default:
assert(0);
break;
}
}
tile->status = LP_TILE_STATUS_UNDEFINED;
}
}
}
}
/**
* Get a tile from the cache.
* \param x, y position of tile, in pixels
*/
void *
lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
unsigned x, unsigned y )
{
struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
struct pipe_transfer *pt = tc->transfer;
assert(tc->surface);
assert(tc->transfer);
if(!tc->transfer_map)
lp_tile_cache_map_transfers(tc);
assert(tc->transfer_map);
switch(tile->status) {
case LP_TILE_STATUS_CLEAR:
/* don't get tile from framebuffer, just clear it */
clear_tile(tile, tc->clear_color);
tile->status = LP_TILE_STATUS_DEFINED;
break;
case LP_TILE_STATUS_UNDEFINED: {
unsigned w = TILE_SIZE;
unsigned h = TILE_SIZE;
x &= ~(TILE_SIZE - 1);
y &= ~(TILE_SIZE - 1);
if (!pipe_clip_tile(x, y, &w, &h, tc->transfer))
lp_tile_read_4ub(pt->texture->format,
tile->color,
tc->transfer_map, tc->transfer->stride,
x, y, w, h);
tile->status = LP_TILE_STATUS_DEFINED;
break;
}
case LP_TILE_STATUS_DEFINED:
/* nothing to do */
break;
}
return tile->color;
}
/**
* When a whole surface is being cleared to a value we can avoid
* fetching tiles above.
* Save the color and set a 'clearflag' for each tile of the screen.
*/
void
lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
uint clearValue)
{
struct pipe_transfer *pt = tc->transfer;
const unsigned w = pt->width;
const unsigned h = pt->height;
unsigned x, y, chan;
for(chan = 0; chan < 4; ++chan)
tc->clear_color[chan] = float_to_ubyte(rgba[chan]);
tc->clear_val = clearValue;
/* push the tile to all positions marked as clear */
for (y = 0; y < h; y += TILE_SIZE) {
for (x = 0; x < w; x += TILE_SIZE) {
struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
tile->status = LP_TILE_STATUS_CLEAR;
}
}
}

View file

@ -0,0 +1,39 @@
/**************************************************************************
*
* Copyright 2010 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, sub license, 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 (including the
* next paragraph) 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
#ifndef LP_TILE_SIZE_H
#define LP_TILE_SIZE_H
/**
* Tile size (width and height). This needs to be a power of two.
*/
#define TILE_ORDER 6
#define TILE_SIZE (1 << TILE_ORDER)
#endif

View file

@ -30,7 +30,7 @@
#include "pipe/p_compiler.h"
#include "tgsi/tgsi_exec.h" /* for NUM_CHANNELS */
#include "lp_tile_size.h"
#ifdef __cplusplus
extern "C" {
@ -40,26 +40,20 @@ extern "C" {
struct pipe_transfer;
/**
* Cache tile size (width and height). This needs to be a power of two.
*/
#define TILE_SIZE 64
#define TILE_VECTOR_HEIGHT 2
#define TILE_VECTOR_WIDTH 8
#define TILE_VECTOR_HEIGHT 4
#define TILE_VECTOR_WIDTH 4
extern const unsigned char
tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH];
#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT*TILE_VECTOR_WIDTH)
#define TILE_X_STRIDE (NUM_CHANNELS*TILE_C_STRIDE)
#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT*TILE_SIZE*NUM_CHANNELS)
#define TILE_C_STRIDE (TILE_VECTOR_HEIGHT * TILE_VECTOR_WIDTH) //16
#define TILE_X_STRIDE (NUM_CHANNELS * TILE_C_STRIDE) //64
#define TILE_Y_STRIDE (TILE_VECTOR_HEIGHT * TILE_SIZE * NUM_CHANNELS) //1024
#define TILE_PIXEL(_p, _x, _y, _c) \
((_p)[((_y)/TILE_VECTOR_HEIGHT)*TILE_Y_STRIDE + \
((_x)/TILE_VECTOR_WIDTH)*TILE_X_STRIDE + \
(_c)*TILE_C_STRIDE + \
((_p)[((_y) / TILE_VECTOR_HEIGHT) * TILE_Y_STRIDE + \
((_x) / TILE_VECTOR_WIDTH) * TILE_X_STRIDE + \
(_c) * TILE_C_STRIDE + \
tile_offset[(_y) % TILE_VECTOR_HEIGHT][(_x) % TILE_VECTOR_WIDTH]])

View file

@ -129,22 +129,8 @@ def generate_format_read(format, dst_type, dst_native_type, dst_suffix):
print
def generate_format_write(format, src_type, src_native_type, src_suffix):
'''Generate the function to write pixels to a particular format'''
name = short_name(format)
dst_native_type = native_type(format)
print 'static void'
print 'lp_tile_%s_write_%s(const %s *src, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, src_suffix, src_native_type)
print '{'
print ' unsigned x, y;'
print ' uint8_t *dst_row = dst + y0*dst_stride;'
print ' for (y = 0; y < h; ++y) {'
print ' %s *dst_pixel = (%s *)(dst_row + x0*%u);' % (dst_native_type, dst_native_type, format.stride())
print ' for (x = 0; x < w; ++x) {'
def compute_inverse_swizzle(format):
'''Return an array[4] of inverse swizzle terms'''
inv_swizzle = [None]*4
if format.colorspace == 'rgb':
for i in range(4):
@ -155,8 +141,86 @@ def generate_format_write(format, src_type, src_native_type, src_suffix):
swizzle = format.out_swizzle[0]
if swizzle < 4:
inv_swizzle[swizzle] = 0
else:
assert False
return inv_swizzle
def pack_rgba(format, src_type, r, g, b, a):
"""Return an expression for packing r, g, b, a into a pixel of the
given format. Ex: '(b << 24) | (g << 16) | (r << 8) | (a << 0)'
"""
assert format.colorspace == 'rgb'
inv_swizzle = compute_inverse_swizzle(format)
shift = 0
expr = None
for i in range(4):
# choose r, g, b, or a depending on the inverse swizzle term
if inv_swizzle[i] == 0:
value = r
elif inv_swizzle[i] == 1:
value = g
elif inv_swizzle[i] == 2:
value = b
elif inv_swizzle[i] == 3:
value = a
else:
value = None
if value:
dst_type = format.in_types[i]
dst_native_type = native_type(format)
value = conversion_expr(src_type, dst_type, dst_native_type, value)
term = "((%s) << %d)" % (value, shift)
if expr:
expr = expr + " | " + term
else:
expr = term
width = format.in_types[i].size
shift = shift + width
return expr
def emit_unrolled_write_code(format, src_type):
'''Emit code for writing a block based on unrolled loops.
This is considerably faster than the TILE_PIXEL-based code below.
'''
dst_native_type = native_type(format)
print ' const unsigned dstpix_stride = dst_stride / %d;' % format.stride()
print ' %s *dstpix = (%s *) dst;' % (dst_native_type, dst_native_type)
print ' unsigned int qx, qy, i;'
print
print ' for (qy = 0; qy < h; qy += TILE_VECTOR_HEIGHT) {'
print ' const unsigned py = y0 + qy;'
print ' for (qx = 0; qx < w; qx += TILE_VECTOR_WIDTH) {'
print ' const unsigned px = x0 + qx;'
print ' const uint8_t *r = src + 0 * TILE_C_STRIDE;'
print ' const uint8_t *g = src + 1 * TILE_C_STRIDE;'
print ' const uint8_t *b = src + 2 * TILE_C_STRIDE;'
print ' const uint8_t *a = src + 3 * TILE_C_STRIDE;'
print ' (void) r; (void) g; (void) b; (void) a; /* silence warnings */'
print ' for (i = 0; i < TILE_C_STRIDE; i += 2) {'
print ' const uint32_t pixel0 = %s;' % pack_rgba(format, src_type, "r[i+0]", "g[i+0]", "b[i+0]", "a[i+0]")
print ' const uint32_t pixel1 = %s;' % pack_rgba(format, src_type, "r[i+1]", "g[i+1]", "b[i+1]", "a[i+1]")
print ' const unsigned offset = (py + tile_y_offset[i]) * dstpix_stride + (px + tile_x_offset[i]);'
print ' dstpix[offset + 0] = pixel0;'
print ' dstpix[offset + 1] = pixel1;'
print ' }'
print ' src += TILE_X_STRIDE;'
print ' }'
print ' }'
def emit_tile_pixel_write_code(format, src_type):
'''Emit code for writing a block based on the TILE_PIXEL macro.'''
dst_native_type = native_type(format)
inv_swizzle = compute_inverse_swizzle(format)
print ' unsigned x, y;'
print ' uint8_t *dst_row = dst + y0*dst_stride;'
print ' for (y = 0; y < h; ++y) {'
print ' %s *dst_pixel = (%s *)(dst_row + x0*%u);' % (dst_native_type, dst_native_type, format.stride())
print ' for (x = 0; x < w; ++x) {'
if format.layout == ARITH:
print ' %s pixel = 0;' % dst_native_type
@ -185,6 +249,20 @@ def generate_format_write(format, src_type, src_native_type, src_suffix):
print ' }'
print ' dst_row += dst_stride;'
print ' }'
def generate_format_write(format, src_type, src_native_type, src_suffix):
'''Generate the function to write pixels to a particular format'''
name = short_name(format)
print 'static void'
print 'lp_tile_%s_write_%s(const %s *src, uint8_t *dst, unsigned dst_stride, unsigned x0, unsigned y0, unsigned w, unsigned h)' % (name, src_suffix, src_native_type)
print '{'
if format.layout == ARITH and format.colorspace == 'rgb':
emit_unrolled_write_code(format, src_type)
else:
emit_tile_pixel_write_code(format, src_type)
print '}'
print
@ -259,8 +337,23 @@ def main():
print
print 'const unsigned char'
print 'tile_offset[TILE_VECTOR_HEIGHT][TILE_VECTOR_WIDTH] = {'
print ' { 0, 1, 4, 5, 8, 9, 12, 13},'
print ' { 2, 3, 6, 7, 10, 11, 14, 15}'
print ' { 0, 1, 4, 5},'
print ' { 2, 3, 6, 7},'
print ' { 8, 9, 12, 13},'
print ' { 10, 11, 14, 15}'
print '};'
print
print '/* Note: these lookup tables could be replaced with some'
print ' * bit-twiddling code, but this is a little faster.'
print ' */'
print 'static unsigned tile_x_offset[TILE_VECTOR_WIDTH * TILE_VECTOR_HEIGHT] = {'
print ' 0, 1, 0, 1, 2, 3, 2, 3,'
print ' 0, 1, 0, 1, 2, 3, 2, 3'
print '};'
print
print 'static unsigned tile_y_offset[TILE_VECTOR_WIDTH * TILE_VECTOR_HEIGHT] = {'
print ' 0, 0, 1, 1, 0, 0, 1, 1,'
print ' 2, 2, 3, 3, 2, 2, 3, 3'
print '};'
print