/* Copyright � 2017, The AROS Development Team. All rights reserved. $Id$ */ //#include #include #include #include #include #include #include "renderer.h" #include "support.h" extern void RenderTile(struct ExecBase *SysBase, struct MsgPort *masterPort, struct MsgPort **myPort); struct Worker { struct Task * task; struct MsgPort *port; char * name; }; struct MyMessage *AllocMyMessage(struct List *msgPool) { struct MyMessage *msg = (struct MyMessage *)RemHead(msgPool); if (msg) { msg->mm_Message.mn_Length = sizeof(struct MyMessage); } return msg; } void FreeMyMessage(struct List *msgPool, struct MyMessage *msg) { AddHead(msgPool, &msg->mm_Message.mn_Node); } void Renderer(struct ExecBase *ExecBase, struct MsgPort *ParentMailbox) { ULONG width = 0; ULONG height = 0; ULONG *bitmap = NULL; struct MsgPort *guiPort = NULL; struct MsgPort *port; struct MyMessage *messages; struct MyMessage *deathMessage = NULL; ULONG numberOfCores = 0; ULONG maxIter = 0; int cores_alive = 0; int tasks_in = 0; int tasks_out = 0; int tasks_work = 0; ULONG workerStack = 0x100000 + maximal_ray_depth * 8192; int expl_mode = 0; //Printf("[SMP-Smallpt-Renderer] Renderer started, ParentMailBox = %p\n", ParentMailbox); port = CreateMsgPort(); if (port) { struct Message startup; int stayAlive = TRUE; struct List workList; struct List doneList; struct List msgPool; struct tileWork *workPackages; struct Worker *workers; NewList(&workList); NewList(&doneList); NewList(&msgPool); /* Prepare initial message and wait for startup msg */ startup.mn_Length = sizeof(startup); startup.mn_ReplyPort = port; #if 0 D(bug("[SMP-Smallpt-Renderer] Sending welcome msg to parent\n")); #endif PutMsg(ParentMailbox, &startup); while(width == 0) { struct MyMessage *msg; WaitPort(port); while ((msg = (struct MyMessage *)GetMsg(port))) { if (msg->mm_Message.mn_Node.ln_Type == NT_REPLYMSG) { #if 0 D(bug("[SMP-Smallpt-Renderer] Parent replied to welcome msg\n")); #endif } else if (msg->mm_Message.mn_Length >= sizeof(struct Message)) { if (msg->mm_Type == MSG_STARTUP) { #if 0 D(bug("[SMP-Smallpt-Renderer] recieved startup message at %p\n", msg)); #endif guiPort = msg->mm_Message.mn_ReplyPort; width = msg->mm_Body.Startup.Width; height = msg->mm_Body.Startup.Height; bitmap = msg->mm_Body.Startup.ChunkyBM; //mainTask = msg->mm_Message.mn_ReplyPort->mp_SigTask; numberOfCores = msg->mm_Body.Startup.coreCount; maxIter = msg->mm_Body.Startup.numberOfSamples; expl_mode = msg->mm_Body.Startup.explicitMode; } ReplyMsg(&msg->mm_Message); } } } #if 0 D(bug("[SMP-Smallpt-Renderer] Bitmap size %dx%d, chunky buffer at %p\n", width, height, bitmap)); #endif ULONG tile_count = (width / TILE_SIZE) * (height / TILE_SIZE); tasks_in = tile_count; workPackages = AllocMem(tile_count * sizeof(struct tileWork), MEMF_ANY); #if 0 D(bug("[SMP-Smallpt-Renderer] Preparing work packages\n")); #endif for (ULONG i=0; i < tile_count; i++) { workPackages[i].x = i % (width / TILE_SIZE); workPackages[i].y = i / (width / TILE_SIZE); AddTail((struct List *)&workList, (struct Node *)&workPackages[i].node); } messages = AllocMem(sizeof(struct MyMessage) * numberOfCores * 10, MEMF_PUBLIC | MEMF_CLEAR); for (int i=0; i < numberOfCores * 10; i++) FreeMyMessage(&msgPool, &messages[i]); #if 0 D(bug("[SMP-Smallpt-Renderer] creating %d workers\n", numberOfCores)); #endif workers = AllocMem(sizeof(struct Worker) * numberOfCores, MEMF_PUBLIC | MEMF_CLEAR); #if 0 D(bug("[SMP-Smallpt-Renderer] worker stack size : %d bytes\n", workerStack)); #endif for (ULONG i=0; i < numberOfCores; i++) { workers[i].name = AllocMem(30, MEMF_PUBLIC | MEMF_CLEAR); _sprintf(workers[i].name, "SMP-SmallPT Worker.#%03u", i); workers[i].task = NewCreateTask(TASKTAG_NAME, (Tag)workers[i].name, TASKTAG_PRI, 0, TASKTAG_PC, (Tag)RenderTile, TASKTAG_ARG1, (Tag)ExecBase, TASKTAG_ARG2, (Tag)port, TASKTAG_ARG3, (Tag)&workers[i].port, TASKTAG_STACKSIZE, workerStack, TAG_DONE); } cores_alive = numberOfCores; #if 0 D(bug("[SMP-Smallpt-Renderer] all set up, doing work\n")); #endif while(stayAlive) { struct MyMessage *msg; WaitPort(port); while ((msg = (struct MyMessage *)GetMsg(port))) { if (msg->mm_Message.mn_Node.ln_Type == NT_REPLYMSG) { if (msg->mm_Type == MSG_DIE) { #if 0 D(bug("[SMP-Smallpt-Renderer] death of smallpt task detected...\n")); #endif cores_alive--; if (cores_alive == 0) { stayAlive = FALSE; ReplyMsg(&deathMessage->mm_Message); } } FreeMyMessage(&msgPool, msg); } else { if (msg->mm_Type == MSG_DIE) { #if 0 D(bug("[SMP-Smallpt-Renderer] time to die...\n")); #endif for (ULONG i=0; i < numberOfCores; i++) { struct MyMessage *m = AllocMyMessage(&msgPool); if (m) { m->mm_Type = MSG_DIE; m->mm_Message.mn_ReplyPort = port; #if 0 D(bug("[SMP-Smallpt-Renderer] telling task %s to shut down\n", workers[i].task->tc_Node.ln_Name)); #endif PutMsg(workers[i].port, &m->mm_Message); } } deathMessage = msg; } else if (msg->mm_Type == MSG_HUNGRY) { struct MsgPort *workerPort = msg->mm_Message.mn_ReplyPort; ReplyMsg(&msg->mm_Message); if (!IsListEmpty((struct List *)&workList)) { struct MyMessage *m = AllocMyMessage(&msgPool); if (m) { struct tileWork *work = (struct tileWork *)RemHead((struct List *)&workList); tasks_in--; tasks_work++; m->mm_Type = MSG_RENDERTILE; m->mm_Message.mn_ReplyPort = port; m->mm_Body.RenderTile.tile = work; m->mm_Body.RenderTile.buffer = bitmap; m->mm_Body.RenderTile.guiPort = guiPort; m->mm_Body.RenderTile.width = width; m->mm_Body.RenderTile.height = height; m->mm_Body.RenderTile.numberOfSamples = maxIter; m->mm_Body.RenderTile.explicitMode = expl_mode; PutMsg(workerPort, &m->mm_Message); } } } else if (msg->mm_Type == MSG_RENDERREADY) { struct tileWork *work = msg->mm_Body.RenderTile.tile; ReplyMsg(&msg->mm_Message); AddHead((struct List *)&doneList, (struct Node *)work); tasks_out++; tasks_work--; if (tasks_in == 0) { Signal(ParentMailbox->mp_SigTask, SIGBREAKF_CTRL_D); } } if (deathMessage == NULL) { struct MyMessage *m = AllocMyMessage(&msgPool); if (m) { m->mm_Type = MSG_STATS; m->mm_Message.mn_ReplyPort = port; m->mm_Body.Stats.tasksIn = tasks_in; m->mm_Body.Stats.tasksOut = tasks_out; m->mm_Body.Stats.tasksWork = tasks_work; PutMsg(guiPort, &m->mm_Message); } } } } } FreeMem(workPackages, tile_count * sizeof(struct tileWork)); FreeMem(messages, sizeof(struct MyMessage) * numberOfCores * 10); FreeMem(workers, sizeof(struct Worker) * numberOfCores); DeleteMsgPort(port); } #if 0 D(bug("[SMP-Smallpt-Renderer] goodbye!\n")); #endif }