+ command->starty = bound(0, dpsoftrast.drawstarty, dpsoftrast.fb_height);
+ command->endy = bound(0, dpsoftrast.drawendy, dpsoftrast.fb_height);
+ if (command->starty >= command->endy)
+ {
+ if (command->commandsize <= DPSOFTRAST_ALIGNCOMMAND(sizeof(DPSOFTRAST_Command_Draw)))
+ MM_FREE(command->arrays);
+ DPSOFTRAST_UndoCommand(command->commandsize);
+ return;
+ }
+ command->clipped = dpsoftrast.drawclipped;
+ command->refcount = dpsoftrast.numthreads;
+
+ if (dpsoftrast.usethreads)
+ {
+ int i;
+ DPSOFTRAST_Draw_SyncCommands();
+ for (i = 0; i < dpsoftrast.numthreads; i++)
+ {
+ DPSOFTRAST_State_Thread *thread = &dpsoftrast.threads[i];
+ if (((command->starty < thread->maxy1 && command->endy > thread->miny1) || (command->starty < thread->maxy2 && command->endy > thread->miny2)) && thread->starving)
+ Thread_CondSignal(thread->drawcond);
+ }
+ }
+ else
+ {
+ DPSOFTRAST_Draw_FlushThreads();
+ }
+}
+
+DEFCOMMAND(23, SetRenderTargets, int width; int height;);
+static void DPSOFTRAST_Interpret_SetRenderTargets(DPSOFTRAST_State_Thread *thread, const DPSOFTRAST_Command_SetRenderTargets *command)
+{
+ thread->validate |= DPSOFTRAST_VALIDATE_FB;
+}
+void DPSOFTRAST_SetRenderTargets(int width, int height, unsigned int *depthpixels, unsigned int *colorpixels0, unsigned int *colorpixels1, unsigned int *colorpixels2, unsigned int *colorpixels3)
+{
+ DPSOFTRAST_Command_SetRenderTargets *command;
+ if (width != dpsoftrast.fb_width || height != dpsoftrast.fb_height || depthpixels != dpsoftrast.fb_depthpixels ||
+ colorpixels0 != dpsoftrast.fb_colorpixels[0] || colorpixels1 != dpsoftrast.fb_colorpixels[1] ||
+ colorpixels2 != dpsoftrast.fb_colorpixels[2] || colorpixels3 != dpsoftrast.fb_colorpixels[3])
+ DPSOFTRAST_Flush();
+ dpsoftrast.fb_width = width;
+ dpsoftrast.fb_height = height;
+ dpsoftrast.fb_depthpixels = depthpixels;
+ dpsoftrast.fb_colorpixels[0] = colorpixels0;
+ dpsoftrast.fb_colorpixels[1] = colorpixels1;
+ dpsoftrast.fb_colorpixels[2] = colorpixels2;
+ dpsoftrast.fb_colorpixels[3] = colorpixels3;
+ DPSOFTRAST_RecalcViewport(dpsoftrast.viewport, dpsoftrast.fb_viewportcenter, dpsoftrast.fb_viewportscale);
+ command = DPSOFTRAST_ALLOCATECOMMAND(SetRenderTargets);
+ command->width = width;
+ command->height = height;
+}
+
+static void DPSOFTRAST_Draw_InterpretCommands(DPSOFTRAST_State_Thread *thread, int endoffset)
+{
+ int commandoffset = thread->commandoffset;
+ while (commandoffset != endoffset)
+ {
+ DPSOFTRAST_Command *command = (DPSOFTRAST_Command *)&dpsoftrast.commandpool.commands[commandoffset];
+ switch (command->opcode)
+ {
+#define INTERPCOMMAND(name) \
+ case DPSOFTRAST_OPCODE_##name : \
+ DPSOFTRAST_Interpret_##name (thread, (DPSOFTRAST_Command_##name *)command); \
+ commandoffset += DPSOFTRAST_ALIGNCOMMAND(sizeof( DPSOFTRAST_Command_##name )); \
+ if (commandoffset >= DPSOFTRAST_DRAW_MAXCOMMANDPOOL) \
+ commandoffset = 0; \
+ break;
+ INTERPCOMMAND(Viewport)
+ INTERPCOMMAND(ClearColor)
+ INTERPCOMMAND(ClearDepth)
+ INTERPCOMMAND(ColorMask)
+ INTERPCOMMAND(DepthTest)
+ INTERPCOMMAND(ScissorTest)
+ INTERPCOMMAND(Scissor)
+ INTERPCOMMAND(BlendFunc)
+ INTERPCOMMAND(BlendSubtract)
+ INTERPCOMMAND(DepthMask)
+ INTERPCOMMAND(DepthFunc)
+ INTERPCOMMAND(DepthRange)
+ INTERPCOMMAND(PolygonOffset)
+ INTERPCOMMAND(CullFace)
+ INTERPCOMMAND(SetTexture)
+ INTERPCOMMAND(SetShader)
+ INTERPCOMMAND(Uniform4f)
+ INTERPCOMMAND(UniformMatrix4f)
+ INTERPCOMMAND(Uniform1i)
+ INTERPCOMMAND(SetRenderTargets)
+ INTERPCOMMAND(ClipPlane)
+
+ case DPSOFTRAST_OPCODE_Draw:
+ DPSOFTRAST_Interpret_Draw(thread, (DPSOFTRAST_Command_Draw *)command);
+ commandoffset += command->commandsize;
+ if (commandoffset >= DPSOFTRAST_DRAW_MAXCOMMANDPOOL)
+ commandoffset = 0;
+ thread->commandoffset = commandoffset;
+ break;
+
+ case DPSOFTRAST_OPCODE_Reset:
+ commandoffset = 0;
+ break;
+ }
+ }
+ thread->commandoffset = commandoffset;
+}
+
+static int DPSOFTRAST_Draw_Thread(void *data)
+{
+ DPSOFTRAST_State_Thread *thread = (DPSOFTRAST_State_Thread *)data;
+ while(thread->index >= 0)
+ {
+ if (thread->commandoffset != dpsoftrast.drawcommand)
+ {
+ DPSOFTRAST_Draw_InterpretCommands(thread, dpsoftrast.drawcommand);
+ }
+ else
+ {
+ Thread_LockMutex(thread->drawmutex);
+ if (thread->commandoffset == dpsoftrast.drawcommand && thread->index >= 0)
+ {
+ if (thread->waiting) Thread_CondSignal(thread->waitcond);
+ thread->starving = true;
+ Thread_CondWait(thread->drawcond, thread->drawmutex);
+ thread->starving = false;
+ }
+ Thread_UnlockMutex(thread->drawmutex);
+ }
+ }
+ return 0;
+}
+
+static void DPSOFTRAST_Draw_FlushThreads(void)
+{
+ DPSOFTRAST_State_Thread *thread;
+ int i;
+ DPSOFTRAST_Draw_SyncCommands();
+ if (dpsoftrast.usethreads)
+ {
+ for (i = 0; i < dpsoftrast.numthreads; i++)
+ {
+ thread = &dpsoftrast.threads[i];
+ if (thread->commandoffset != dpsoftrast.drawcommand)
+ {
+ Thread_LockMutex(thread->drawmutex);
+ if (thread->commandoffset != dpsoftrast.drawcommand && thread->starving)
+ Thread_CondSignal(thread->drawcond);
+ Thread_UnlockMutex(thread->drawmutex);
+ }
+ }
+ for (i = 0; i < dpsoftrast.numthreads; i++)
+ {
+ thread = &dpsoftrast.threads[i];
+ if (thread->commandoffset != dpsoftrast.drawcommand)
+ {
+ Thread_LockMutex(thread->drawmutex);
+ if (thread->commandoffset != dpsoftrast.drawcommand)
+ {
+ thread->waiting = true;
+ Thread_CondWait(thread->waitcond, thread->drawmutex);
+ thread->waiting = false;
+ }
+ Thread_UnlockMutex(thread->drawmutex);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < dpsoftrast.numthreads; i++)
+ {
+ thread = &dpsoftrast.threads[i];
+ if (thread->commandoffset != dpsoftrast.drawcommand)
+ DPSOFTRAST_Draw_InterpretCommands(thread, dpsoftrast.drawcommand);
+ }
+ }
+ dpsoftrast.commandpool.usedcommands = 0;
+}
+
+void DPSOFTRAST_Flush(void)
+{
+ DPSOFTRAST_Draw_FlushThreads();