blob: 7f60b325bb81ae1933631e27243e624ac7d14fd5 [file] [log] [blame]
//TODO: copyrights
#include "worker.h"
#include "device.h"
#include "buffer.h"
#include "kernel.h"
#include "builtins.h"
#include "commandqueue.h"
#include "events.h"
#include "memobject.h"
#include "kernel.h"
#include <cstring>
#include <iostream>
using namespace Devices;
void worker(void *data)
{
CPUDevice *device = (CPUDevice *)data;
bool stop = false;
cl_int errcode;
Event *event;
// Initialize TLS
setWorkItemsData(0, 0);
while(true)
{
event = device->getEvent(stop);
// Ensure we have a good event and we don't have to stop
if(stop) break;
if(!event) continue;
// Get info about the event and its command queue
Event::Type t = event->type();
CommandQueue *queue = 0;
cl_command_queue_properties queue_props = 0;
errcode = CL_SUCCESS;
event->info(CL_EVENT_COMMAND_QUEUE, sizeof(CommandQueue *), &queue, 0);
if(queue)
queue->info(CL_QUEUE_PROPERTIES, sizeof(cl_command_queue_properties),
&queue_props, 0);
if(queue_props & CL_QUEUE_PROFILING_ENABLE)
event->updateTiming(Event::Start);
// Execute the action
switch(t)
{
case Event::ReadBuffer:
case Event::WriteBuffer:
{
ReadWriteBufferEvent *e = (ReadWriteBufferEvent *)event;
CPUBuffer *buf = (CPUBuffer *)e->buffer()->deviceBuffer(device);
char *data = (char *)buf->data();
data += e->offset();
if(t == Event::ReadBuffer)
std::memcpy(e->ptr(), data, e->cb());
else
std::memcpy(data, e->ptr(), e->cb());
break;
}
case Event::CopyBuffer:
{
CopyBufferEvent *e = (CopyBufferEvent *)event;
CPUBuffer *src = (CPUBuffer *)e->source()->deviceBuffer(device);
CPUBuffer *dst = (CPUBuffer *)e->destination()->deviceBuffer(device);
std::memcpy(dst->data(), src->data(), e->cb());
break;
}
case Event::ReadBufferRect:
case Event::WriteBufferRect:
case Event::CopyBufferRect:
case Event::ReadImage:
case Event::WriteImage:
case Event::CopyImage:
case Event::CopyBufferToImage:
case Event::CopyImageToBuffer:
{
// src = buffer and dst = mem if note copy
ReadWriteCopyBufferRectEvent *e = (ReadWriteCopyBufferRectEvent *)event;
CPUBuffer *src_buf = (CPUBuffer *)e->source()->deviceBuffer(device);
unsigned char *src = (unsigned char *)src_buf->data();
unsigned char *dst;
switch(t)
{
case Event::CopyBufferRect:
case Event::CopyImage:
case Event::CopyImageToBuffer:
case Event::CopyBufferToImage:
{
CopyBufferRectEvent *cbre = (CopyBufferRectEvent *)e;
CPUBuffer *dst_buf =
(CPUBuffer *)cbre->destination()->deviceBuffer(device);
dst = (unsigned char *)dst_buf->data();
break;
}
default:
{
// dst = host memory location
ReadWriteBufferRectEvent *rwbre = (ReadWriteBufferRectEvent *)e;
dst = (unsigned char *)rwbre->ptr();
}
}
// Iterate over the lines to copy and use memcpy
for(size_t z = 0; z<e->region(2); ++z)
{
for(size_t y = 0; y<e->region(1); ++y)
{
unsigned char *s;
unsigned char *d;
d = imageData(dst,
e->dst_origin(0),
y + e->dst_origin(1),
z + e->dst_origin(2),
e->dst_row_pitch(),
e->dst_slice_pitch(),
1);
s = imageData(src,
e->src_origin(0),
y + e->src_origin(1),
z + e->src_origin(2),
e->src_row_pitch(),
e->src_slice_pitch(),
1);
// Copying and image to a buffer may need to add an offset
// to the buffer address (its rectangular origin is
// always (0, 0, 0)).
if(t == Event::CopyBufferToImage)
{
CopyBufferToImageEvent *cptie = (CopyBufferToImageEvent *)e;
s += cptie->offset();
}
else if(t == Event::CopyImageToBuffer)
{
CopyImageToBufferEvent *citbe = (CopyImageToBufferEvent *)e;
d += citbe->offset();
}
if(t == Event::WriteBufferRect || t == Event::WriteImage)
std::memcpy(s, d, e->region(0)); // Write dest (memory) in src
else
std::memcpy(d, s, e->region(0)); // Write src (buffer) in dest (memory), or copy the buffers
}
}
break;
}
case Event::MapBuffer:
case Event::MapImage:
// All was already done in CPUBuffer::initEventDeviceData()
break;
case Event::NativeKernel:
{
NativeKernelEvent *e = (NativeKernelEvent *)event;
void(*func)(void *) = (void(*)(void *))e->function();
void *args = e->args();
func(args);
break;
}
case Event::NDRangeKernel:
case Event::TaskKernel:
{
KernelEvent *e = (KernelEvent *)event;
CPUKernelEvent *ke = (CPUKernelEvent *)e->deviceData();
// Take an instance
CPUKernelWorkGroup *instance = ke->takeInstance();
ke = 0; // Unlocked, don't use anymore
if(!instance->run())
errcode = CL_INVALID_PROGRAM_EXECUTABLE;
delete instance;
break;
}
default:
break;
}
// Cleanups
if(errcode == CL_SUCCESS)
{
bool finished = true;
if(event->type() == Event::NDRangeKernel ||
event->type() == Event::TaskKernel)
{
CPUKernelEvent *ke = (CPUKernelEvent *)event->deviceData();
finished = ke->finished();
}
if(finished)
{
event->setStatus(Event::Complete);
if(queue_props & CL_QUEUE_PROFILING_ENABLE)
event->updateTiming(Event::End);
// Clean the queue
if(queue)
queue->cleanEvents();
}
}
else
{
// The event failed
event->setStatus((Event::Status)errcode);
if(queue_props & CL_QUEUE_PROFILING_ENABLE)
event->updateTiming(Event::End);
}
}
// Free mmapped() data if needed
size_t mapped_size;
void *mapped_data = getWorkItemsData(mapped_size);
/*if(mapped_data)
munmap(mapped_data, mapped_size);*/
}