initial commit

This commit is contained in:
foreman
2014-07-04 16:17:05 -04:00
parent dc4af184c7
commit 3694ab2ce8
351 changed files with 113713 additions and 1 deletions
+530
View File
@@ -0,0 +1,530 @@
//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/agent.hpp"
#include "platform/object.hpp"
#include "os/os.hpp"
#include "amdocl/cl_common.hpp"
#include <cstdlib>
#include <cstring>
#include <string>
#include <sstream>
namespace amd {
typedef cl_int (CL_CALLBACK * clAgent_OnLoad_fn)(cl_agent * agent);
typedef void (CL_CALLBACK * clAgent_OnUnload_fn)(cl_agent * agent);
Agent::Agent(const char* moduleName) :
ready_(false)
{
::memset(&callbacks_, '\0', sizeof(callbacks_));
::memset(&capabilities_, '\0', sizeof(capabilities_));
library_ = Os::loadLibrary(moduleName);
if (library_ == NULL) {
return;
}
clAgent_OnLoad_fn onLoad = reinterpret_cast<clAgent_OnLoad_fn>(
Os::getSymbol(library_, "clAgent_OnLoad"));
if (onLoad == NULL) {
return;
}
_cl_agent* agent = static_cast<_cl_agent*>(this);
::memcpy(agent, &entryPoints_, sizeof(entryPoints_));
// Register in the agents linked-list.
next_ = list_;
list_ = this;
if (onLoad(agent) != CL_SUCCESS) {
list_ = list_->next_;
}
// Mark this instance as ready for use.
ready_ = true;
}
Agent::~Agent()
{
if (library_ != NULL) {
clAgent_OnUnload_fn onUnload = reinterpret_cast<clAgent_OnUnload_fn>(
Os::getSymbol(library_, "clAgent_OnUnload"));
if (onUnload != NULL) {
onUnload(static_cast<cl_agent*>(this));
}
Os::unloadLibrary(library_);
}
}
cl_int
Agent::setCallbacks(const cl_agent_callbacks *callbacks, size_t size)
{
// FIXME_lmoriche: check size
memcpy(&callbacks_, callbacks, size);
return CL_SUCCESS;
}
cl_int
Agent::getCapabilities(cl_agent_capabilities* caps)
{
if (caps == NULL) {
return CL_INVALID_VALUE;
}
*caps = capabilities_;
return CL_SUCCESS;
}
static inline cl_agent_capabilities
operator ~ (const cl_agent_capabilities& src)
{
cl_agent_capabilities result;
const char* a = reinterpret_cast<const char*>(&src);
char *b = reinterpret_cast<char*>(&result);
for (size_t i = 0; i < sizeof(cl_agent_capabilities); ++i) {
*b++ = ~*a++;
}
return result;
}
static inline cl_agent_capabilities
operator | (const cl_agent_capabilities& lhs, const cl_agent_capabilities& rhs)
{
cl_agent_capabilities result;
const char* a = reinterpret_cast<const char*>(&lhs);
const char* b = reinterpret_cast<const char*>(&rhs);
char *c = reinterpret_cast<char*>(&result);
for (size_t i = 0; i < sizeof(cl_agent_capabilities); ++i) {
*c++ = *a++ | *b++;
}
return result;
}
static inline cl_agent_capabilities
operator & (const cl_agent_capabilities& lhs, const cl_agent_capabilities& rhs)
{
cl_agent_capabilities result;
const char* a = reinterpret_cast<const char*>(&lhs);
const char* b = reinterpret_cast<const char*>(&rhs);
char *c = reinterpret_cast<char*>(&result);
for (size_t i = 0; i < sizeof(cl_agent_capabilities); ++i) {
*c++ = *a++ & *b++;
}
return result;
}
static inline bool
operator == (const cl_agent_capabilities& lhs, const cl_agent_capabilities& rhs)
{
const char* a = reinterpret_cast<const char*>(&lhs);
const char* b = reinterpret_cast<const char*>(&rhs);
for (size_t i = 0; i < sizeof(cl_agent_capabilities); ++i) {
if (*a++ != *b++) {
return false;
}
}
return true;
}
static inline bool
operator != (const cl_agent_capabilities& lhs, const cl_agent_capabilities& rhs)
{
return !(lhs == rhs);
}
cl_int
Agent::setCapabilities(const cl_agent_capabilities* caps, bool install)
{
ScopedLock sl(capabilitiesLock_);
if (caps == NULL || *caps != (*caps & potentialCapabilities_)) {
return CL_INVALID_VALUE;
}
if (install) {
capabilities_ = capabilities_ | *caps;
}
else {
capabilities_ = capabilities_ & ~*caps;
}
memset(&enabledCapabilities_, '\0', sizeof(enabledCapabilities_));
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
enabledCapabilities_ = enabledCapabilities_ | agent->capabilities_;
}
return CL_SUCCESS;
}
bool
Agent::init()
{
::memset(&potentialCapabilities_, '\0', sizeof(potentialCapabilities_));
potentialCapabilities_.canGenerateContextEvents = 1;
potentialCapabilities_.canGenerateCommandQueueEvents = 1;
potentialCapabilities_.canGenerateEventEvents = 1;
// potentialCapabilities_.canGenerateMemObjectEvents = 1;
// potentialCapabilities_.canGenerateSamplerEvents = 1;
// potentialCapabilities_.canGenerateProgramEvents = 1;
// potentialCapabilities_.canGenerateKernelEvents = 1;
const char* envVar = ::getenv("CL_AGENT");
if (envVar == NULL) {
return true;
}
std::string token, modules = envVar;
std::istringstream iss(modules);
while (getline(iss, token, ',')) {
Agent* agent = new Agent(token.c_str());
if (agent == NULL || !agent->isReady()) {
delete agent;
// Only return an error if we failed the Agent allocation. Other
// error (the agent is not ready) can be ignored.
return agent != NULL;
}
}
return true;
}
void
Agent::tearDown()
{
while (list_ != NULL) {
Agent* agent = list_;
list_ = list_->next_;
delete agent;
}
}
namespace agent {
static cl_int CL_API_CALL
GetVersionNumber(
cl_agent* agent, cl_int* version_ret)
{
if (version_ret == NULL) {
return CL_INVALID_VALUE;
}
*version_ret = CL_AGENT_VERSION_1_0;
return CL_SUCCESS;
}
static cl_int CL_API_CALL
GetPlatform(
cl_agent* agent, cl_platform_id* platform_id_ret)
{
if (platform_id_ret == NULL) {
return CL_INVALID_VALUE;
}
*platform_id_ret = AMD_PLATFORM;
return CL_SUCCESS;
}
static cl_int CL_API_CALL
GetTime(
cl_agent* agent, cl_long* time_nanos)
{
if (time_nanos == NULL) {
return CL_INVALID_VALUE;
}
*time_nanos = Os::timeNanos() + Os::offsetToEpochNanos();
return CL_SUCCESS;
}
static cl_int CL_API_CALL
SetCallbacks(
cl_agent* agent,
const cl_agent_callbacks* callbacks,
size_t size)
{
return Agent::get(agent)->setCallbacks(callbacks, size);
}
static cl_int CL_API_CALL
GetPotentialCapabilities(
cl_agent* agent, cl_agent_capabilities* capabilities)
{
if (capabilities == NULL) {
return CL_INVALID_VALUE;
}
*capabilities = Agent::potentialCapabilities();
return CL_SUCCESS;
}
static cl_int CL_API_CALL
GetCapabilities(
cl_agent* agent, cl_agent_capabilities* capabilities)
{
return Agent::get(agent)->getCapabilities(capabilities);
}
static cl_int CL_API_CALL
SetCapabilities(
cl_agent* agent,
const cl_agent_capabilities* capabilities,
cl_agent_capability_action action)
{
return Agent::get(agent)->setCapabilities(
capabilities, action == CL_AGENT_ADD_CAPABILITIES);
}
static cl_int CL_API_CALL
GetICDDispatchTable(
cl_agent* agent, cl_icd_dispatch_table* table, size_t size)
{
// FIXME_lmoriche: check size
memcpy(table, amd::ICDDispatchedObject::icdVendorDispatch_, size);
return CL_SUCCESS;
}
static cl_int CL_API_CALL
SetICDDispatchTable(
cl_agent* agent, const cl_icd_dispatch_table* table, size_t size)
{
// FIXME_lmoriche: check size
memcpy(amd::ICDDispatchedObject::icdVendorDispatch_, table, size);
return CL_SUCCESS;
}
} // namespace agent
cl_agent
Agent::entryPoints_ = {
agent::GetVersionNumber,
agent::GetPlatform,
agent::GetTime,
agent::SetCallbacks,
agent::GetPotentialCapabilities,
agent::GetCapabilities,
agent::SetCapabilities,
agent::GetICDDispatchTable,
agent::SetICDDispatchTable
};
void
Agent::postContextCreate(cl_context context)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acContextCreate_fn callback = agent->callbacks_.ContextCreate;
if (callback != NULL && agent->canGenerateContextEvents()) {
callback(agent, context);
}
}
}
void
Agent::postContextFree(cl_context context)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acContextFree_fn callback = agent->callbacks_.ContextFree;
if (callback != NULL && agent->canGenerateContextEvents()) {
callback(agent, context);
}
}
}
void
Agent::postCommandQueueCreate(cl_command_queue queue)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acCommandQueueCreate_fn callback = agent->callbacks_.CommandQueueCreate;
if (callback != NULL && agent->canGenerateCommandQueueEvents()) {
callback(agent, queue);
}
}
}
void
Agent::postCommandQueueFree(cl_command_queue queue)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acCommandQueueFree_fn callback = agent->callbacks_.CommandQueueFree;
if (callback != NULL && agent->canGenerateCommandQueueEvents()) {
callback(agent, queue);
}
}
}
void
Agent::postEventCreate(cl_event event, cl_command_type type)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acEventCreate_fn callback = agent->callbacks_.EventCreate;
if (callback != NULL && agent->canGenerateEventEvents()) {
callback(agent, event, type);
}
}
}
void
Agent::postEventFree(cl_event event)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acEventFree_fn callback = agent->callbacks_.EventFree;
if (callback != NULL && agent->canGenerateEventEvents()) {
callback(agent, event);
}
}
}
void
Agent::postEventStatusChanged(cl_event event, cl_int status, cl_long ts)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acEventStatusChanged_fn callback = agent->callbacks_.EventStatusChanged;
if (callback != NULL && agent->canGenerateEventEvents()) {
callback(agent, event, status, ts);
}
}
}
void
Agent::postMemObjectCreate(cl_mem memobj)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acMemObjectCreate_fn callback = agent->callbacks_.MemObjectCreate;
if (callback != NULL && agent->canGenerateMemObjectEvents()) {
callback(agent, memobj);
}
}
}
void
Agent::postMemObjectFree(cl_mem memobj)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acMemObjectFree_fn callback = agent->callbacks_.MemObjectFree;
if (callback != NULL && agent->canGenerateMemObjectEvents()) {
callback(agent, memobj);
}
}
}
void
Agent::postMemObjectAcquired(
cl_mem memobj, cl_device_id device, cl_long elapsed)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acMemObjectAcquired_fn callback = agent->callbacks_.MemObjectAcquired;
if (callback != NULL && agent->canGenerateMemObjectEvents()) {
callback(agent, memobj, device, elapsed);
}
}
}
void
Agent::postSamplerCreate(cl_sampler sampler)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acSamplerCreate_fn callback = agent->callbacks_.SamplerCreate;
if (callback != NULL && agent->canGenerateSamplerEvents()) {
callback(agent, sampler);
}
}
}
void
Agent::postSamplerFree(cl_sampler sampler)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acSamplerFree_fn callback = agent->callbacks_.SamplerFree;
if (callback != NULL && agent->canGenerateSamplerEvents()) {
callback(agent, sampler);
}
}
}
void
Agent::postProgramCreate(cl_program program)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acProgramCreate_fn callback = agent->callbacks_.ProgramCreate;
if (callback != NULL && agent->canGenerateProgramEvents()) {
callback(agent, program);
}
}
}
void
Agent::postProgramFree(cl_program program)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acProgramFree_fn callback = agent->callbacks_.ProgramFree;
if (callback != NULL && agent->canGenerateProgramEvents()) {
callback(agent, program);
}
}
}
void
Agent::postProgramBuild(cl_program program)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acProgramBuild_fn callback = agent->callbacks_.ProgramBuild;
if (callback != NULL && agent->canGenerateProgramEvents()) {
callback(agent, program);
}
}
}
void
Agent::postKernelCreate(cl_kernel kernel)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acKernelCreate_fn callback = agent->callbacks_.KernelCreate;
if (callback != NULL && agent->canGenerateKernelEvents()) {
callback(agent, kernel);
}
}
}
void
Agent::postKernelFree(cl_kernel kernel)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acKernelFree_fn callback = agent->callbacks_.KernelFree;
if (callback != NULL && agent->canGenerateKernelEvents()) {
callback(agent, kernel);
}
}
}
void
Agent::postKernelSetArg(
cl_kernel kernel, cl_int index, size_t size, const void* value_ptr)
{
for (Agent* agent = list_; agent != NULL; agent = agent->next_) {
acKernelSetArg_fn callback = agent->callbacks_.KernelSetArg;
if (callback != NULL && agent->canGenerateKernelEvents()) {
callback(agent, kernel, index, size, value_ptr);
}
}
}
Agent* Agent::list_ = NULL;
Monitor Agent::capabilitiesLock_;
cl_agent_capabilities Agent::enabledCapabilities_ = { 0 };
cl_agent_capabilities Agent::potentialCapabilities_ = { 0 };
} // namespace amd
+150
View File
@@ -0,0 +1,150 @@
//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef AGENT_HPP_
#define AGENT_HPP_
#include "top.hpp"
#include "thread/monitor.hpp"
#include "amdocl/cl_agent_amd.h"
namespace amd {
class Agent : public _cl_agent
{
private:
//! Linked list of agent instances
static Agent* list_;
//! Agent API entry points
static cl_agent entryPoints_;
//! Capabilities supported by this Agent implementation
static cl_agent_capabilities potentialCapabilities_;
//! Union of all agent's enabled capabilities
static cl_agent_capabilities enabledCapabilities_;
//! Monitor to protect the global capabilities
static Monitor capabilitiesLock_;
public:
//! Initialize the OpenCL agent
static bool init();
//! Teardown the agent.
static void tearDown();
//! Return the capabilities supported by this agent.
static cl_agent_capabilities potentialCapabilities() {
return potentialCapabilities_;
}
#define AGENT_FLAG(name) \
inline static bool shouldPost##name() { \
return enabledCapabilities_.canGenerate##name != 0; \
}
AGENT_FLAG(ContextEvents);
AGENT_FLAG(CommandQueueEvents);
AGENT_FLAG(EventEvents);
AGENT_FLAG(MemObjectEvents);
AGENT_FLAG(SamplerEvents);
AGENT_FLAG(ProgramEvents);
AGENT_FLAG(KernelEvents);
#undef AGENT_FLAG
//! Post a context creation event
static void postContextCreate(cl_context context);
//! Post a context destruction event
static void postContextFree(cl_context context);
//! Post a command queue creation event
static void postCommandQueueCreate(cl_command_queue queue);
//! Post a command queue destruction event
static void postCommandQueueFree(cl_command_queue queue);
//! Post an event creation event
static void postEventCreate(cl_event event, cl_command_type type);
//! Post an event destruction event
static void postEventFree(cl_event event);
//! Post and event status change event.
static void postEventStatusChanged(
cl_event event, cl_int execution_status, cl_long epoch_timestamp);
//! Post a memory object creation event
static void postMemObjectCreate(cl_mem memobj);
//! Post a memory object destruction event
static void postMemObjectFree(cl_mem memobj);
//! Post a memory transfer (acquired by device) event
static void postMemObjectAcquired(
cl_mem memobj, cl_device_id device, cl_long elapsed_time);
//! Post a sampler creation event
static void postSamplerCreate(cl_sampler sampler);
//! Post a sampler destruction event
static void postSamplerFree(cl_sampler sampler);
//! Post a program creation event
static void postProgramCreate(cl_program program);
//! Post a program destruction event
static void postProgramFree(cl_program program);
//! Post a program build event
static void postProgramBuild(cl_program program);
//! Post a kernel creation event
static void postKernelCreate(cl_kernel kernel);
//! Post a kernel destruction event
static void postKernelFree(cl_kernel kernel);
//! Post a kernel set argument event
static void postKernelSetArg(
cl_kernel kernel, cl_int arg_index, size_t size, const void* value_ptr);
private:
Agent* next_; //!< Next agent in the linked-list.
void* library_; //!< Handle to the loaded module.
bool ready_; //!< Is this instance ready?
//! Callbacks vector.
cl_agent_callbacks callbacks_;
//! Capabilities for this agent.
cl_agent_capabilities capabilities_;
#define AGENT_FLAG(name) \
inline bool canGenerate##name() { \
return capabilities_.canGenerate##name != 0; \
}
AGENT_FLAG(ContextEvents);
AGENT_FLAG(CommandQueueEvents);
AGENT_FLAG(EventEvents);
AGENT_FLAG(MemObjectEvents);
AGENT_FLAG(SamplerEvents);
AGENT_FLAG(ProgramEvents);
AGENT_FLAG(KernelEvents);
#undef AGENT_FLAG
public:
//! Construct a new agent.
Agent(const char* moduleName);
//! Destroy the agent
~Agent();
//! Return true if this instance is ready for use.
bool isReady() const { return ready_; }
//! Set the callback vector for this agent
cl_int setCallbacks(const cl_agent_callbacks *callbacks, size_t size);
//! Return the current capabilities.
cl_int getCapabilities(cl_agent_capabilities* caps);
//! Set the current capabilities.
cl_int setCapabilities(const cl_agent_capabilities* caps, bool install);
//! Return the Agent instance from the given cl_agent
inline static Agent* get(cl_agent* agent) {
return const_cast<Agent*>(static_cast<const Agent*>(agent));
}
};
} // namespace amd
#endif // AGENT_HPP_
+578
View File
@@ -0,0 +1,578 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
/*!
* \file command.cpp
* \brief Definitions for Event, Command and HostQueue objects.
*
* \author Laurent Morichetti (laurent.morichetti@amd.com)
* \date October 2008
*/
#include "platform/command.hpp"
#include "platform/commandqueue.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"
#include "platform/kernel.hpp"
#include "thread/monitor.hpp"
#include "platform/memory.hpp"
#include "platform/agent.hpp"
#include "os/alloc.hpp"
#include <cstring>
#include <algorithm>
namespace amd {
Event::Event(HostQueue& queue)
: context_(queue.context())
, callbacks_(NULL)
, status_(CL_INT_MAX)
, notified_(0)
, profilingInfo_(
queue.properties().test(CL_QUEUE_PROFILING_ENABLE)
|| Agent::shouldPostEventEvents())
{ }
Event::Event(Context& context)
: context_(context)
, callbacks_(NULL)
, status_(CL_SUBMITTED)
, notified_(0)
{ }
Event::~Event()
{
CallBackEntry* callback = callbacks_;
while (callback != NULL) {
CallBackEntry* next = callback->next_;
delete callback;
callback = next;
}
}
uint64_t
Event::recordProfilingInfo(cl_int status, uint64_t timeStamp)
{
if (timeStamp == 0) {
timeStamp = Os::timeNanos();
}
switch (status) {
case CL_QUEUED:
profilingInfo_.queued_ = timeStamp;
break;
case CL_SUBMITTED:
profilingInfo_.submitted_ = timeStamp;
break;
case CL_RUNNING:
profilingInfo_.start_ = timeStamp;
break;
default:
profilingInfo_.end_ = timeStamp;
break;
}
return timeStamp;
}
bool
Event::setStatus(cl_int status, uint64_t timeStamp)
{
assert(status <= CL_QUEUED && "invalid status");
cl_int currentStatus = status_;
if (currentStatus <= CL_COMPLETE || currentStatus <= status) {
// We can only move forward in the execution status.
return false;
}
if (profilingInfo().enabled_) {
timeStamp = recordProfilingInfo(status, timeStamp);
}
if (!make_atomic(status_).compareAndSet(currentStatus, status)) {
// Somebody else beat us to it, let them deal with the release/signal.
return false;
}
if (callbacks_ != NULL) {
processCallbacks(status);
}
if (Agent::shouldPostEventEvents() && command().type() != 0) {
Agent::postEventStatusChanged(
as_cl(this), status, timeStamp + Os::offsetToEpochNanos());
}
if (status <= CL_COMPLETE) {
// Before we notify the waiters that this event reached the CL_COMPLETE
// status, we release all the resources associated with this instance.
releaseResources();
// Broadcast all the waiters.
if (referenceCount() > 1) {
signal();
}
release();
}
return true;
}
bool
Event::setCallback(cl_int status, Event::CallBackFunction callback, void* data)
{
assert(status >= CL_COMPLETE && status <= CL_QUEUED && "invalid status");
CallBackEntry* entry = new CallBackEntry(status, callback, data);
if (entry == NULL) {
return false;
}
entry->next_ = callbacks_;
while (!callbacks_.compareAndSet(entry->next_, entry)) {
// Someone else is also updating the head of the linked list! reload.
entry->next_ = callbacks_;
}
// Check if the event has already reached 'status'
if (status_ <= status && entry->callback_ != NULL) {
if (entry->callback_.swap(NULL) != NULL) {
callback(as_cl(this), status, entry->data_);
}
}
return true;
}
void
Event::processCallbacks(cl_int status) const
{
cl_event event = const_cast<cl_event>(as_cl(this));
const cl_int mask = (status > CL_COMPLETE) ? status : CL_COMPLETE;
// For_each callback:
CallBackEntry* entry;
for (entry = callbacks_; entry != NULL; entry = entry->next_) {
// If the entry's status matches the mask,
if (entry->status_ == mask && entry->callback_ != NULL) {
// invoke the callback function.
CallBackFunction callback = entry->callback_.swap(NULL);
if (callback != NULL) {
callback(event, status, entry->data_);
}
}
}
}
bool
Event::awaitCompletion()
{
if (status_ > CL_COMPLETE) {
// Notifies current command queue about waiting
if (!notifyCmdQueue()) {
return false;
}
ScopedLock lock(lock_);
// Wait until the status becomes CL_COMPLETE or negative.
while (status_ > CL_COMPLETE) {
lock_.wait();
}
}
return status_ == CL_COMPLETE;
}
bool
Event::notifyCmdQueue()
{
static uint Notifed = 1;
static uint Empty = 0;
HostQueue* queue = command().queue();
if ((NULL != queue) && notified_.compareAndSet(Empty, Notifed)) {
// Make sure the queue is draining the enqueued commands.
amd::Command* command = new amd::Marker(*queue, false, nullWaitList, this);
if (command == NULL) {
notified_.compareAndSet(Notifed, Empty);
return false;
}
command->enqueue();
command->release();
}
return true;
}
const Event::EventWaitList Event::nullWaitList(0);
Command::Command(
HostQueue& queue,
cl_command_type type,
const EventWaitList& eventWaitList) :
Event(queue), queue_(&queue), next_(NULL), type_(type),
exception_(0), data_(NULL), eventWaitList_(eventWaitList)
{
// Retain the commands from the event wait list.
std::for_each(
eventWaitList.begin(),
eventWaitList.end(),
std::mem_fun(&Command::retain));
}
Command::~Command()
{
const Command::EventWaitList& events = eventWaitList();
// Release the commands from the event wait list.
std::for_each(
events.begin(),
events.end(),
std::mem_fun(&Command::release));
}
void
Command::releaseResources()
{
}
void
Command::enqueue()
{
assert(queue_ != NULL && "Cannot be enqueued");
if (Agent::shouldPostEventEvents() && type_ != 0) {
Agent::postEventCreate(as_cl(static_cast<Event*>(this)), type_);
}
queue_->append(*this);
queue_->flush();
if (queue_->device().settings().waitCommand_ && (type_ != 0)) {
awaitCompletion();
}
}
NDRangeKernelCommand::NDRangeKernelCommand(
HostQueue& queue,
const EventWaitList& eventWaitList,
Kernel& kernel,
const NDRangeContainer& sizes) :
Command(queue, CL_COMMAND_NDRANGE_KERNEL, eventWaitList),
kernel_(kernel), sizes_(sizes)
{
parameters_ = kernel.parameters().capture(queue.device());
fixme_guarantee(parameters_ != NULL && "out of memory");
kernel_.retain();
}
void NDRangeKernelCommand::releaseResources() {
kernel_.parameters().release(parameters_, queue()->device());
DEBUG_ONLY(parameters_ = NULL);
kernel_.release();
Command::releaseResources();
}
NativeFnCommand::NativeFnCommand(
HostQueue& queue, const EventWaitList& eventWaitList,
void (CL_CALLBACK *nativeFn)(void*), const void* args, size_t argsSize,
size_t numMemObjs, const cl_mem* memObjs, const void** memLocs) :
Command(queue, CL_COMMAND_NATIVE_KERNEL, eventWaitList),
nativeFn_(nativeFn), argsSize_(argsSize)
{
args_ = new char[argsSize_];
if (args_ == NULL) {
return;
}
::memcpy(args_, args, argsSize_);
memObjects_.resize(numMemObjs);
memOffsets_.resize(numMemObjs);
for (size_t i = 0; i < numMemObjs; ++i) {
Memory* obj = as_amd(memObjs[i]);
obj->retain();
memObjects_[i] = obj;
memOffsets_[i] = (const_address) memLocs[i] - (const_address) args;
}
}
cl_int
NativeFnCommand::invoke()
{
size_t numMemObjs = memObjects_.size();
for (size_t i = 0; i < numMemObjs; ++i) {
void* hostMemPtr = memObjects_[i]->getHostMem();
if (hostMemPtr == NULL) {
return CL_MEM_OBJECT_ALLOCATION_FAILURE;
}
*reinterpret_cast<void **>(&args_[memOffsets_[i]]) = hostMemPtr;
}
nativeFn_(args_);
return CL_SUCCESS;
}
bool
OneMemoryArgCommand::validateMemory()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
device::Memory* mem = memory_->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
memory_->getSize());
return false;
}
}
return true;
}
bool
TwoMemoryArgsCommand::validateMemory()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
device::Memory* mem = memory1_->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
memory1_->getSize());
return false;
}
mem = memory2_->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
memory2_->getSize());
return false;
}
}
return true;
}
bool
ReadMemoryCommand::isEntireMemory() const
{
return source().isEntirelyCovered(origin(), size());
}
bool
WriteMemoryCommand::isEntireMemory() const
{
return destination().isEntirelyCovered(origin(), size());
}
bool
SvmMapMemoryCommand::isEntireMemory() const
{
return getSvmMem()->isEntirelyCovered(origin(), size());
}
bool
FillMemoryCommand::isEntireMemory() const
{
return memory().isEntirelyCovered(origin(), size());
}
bool
CopyMemoryCommand::isEntireMemory() const
{
bool result = false;
switch (type()) {
case CL_COMMAND_COPY_IMAGE_TO_BUFFER: {
Coord3D imageSize(size()[0] * size()[1] * size()[2] *
source().asImage()->getImageFormat().getElementSize());
result = source().isEntirelyCovered(srcOrigin(), size()) &&
destination().isEntirelyCovered(dstOrigin(), imageSize);
}
break;
case CL_COMMAND_COPY_BUFFER_TO_IMAGE: {
Coord3D imageSize(size()[0] * size()[1] * size()[2] *
destination().asImage()->getImageFormat().getElementSize());
result = source().isEntirelyCovered(srcOrigin(), imageSize) &&
destination().isEntirelyCovered(dstOrigin(), size());
}
break;
case CL_COMMAND_COPY_BUFFER_RECT: {
Coord3D rectSize(size()[0] * size()[1] * size()[2]);
Coord3D srcOffs(srcRect().start_);
Coord3D dstOffs(dstRect().start_);
result = source().isEntirelyCovered(srcOffs, rectSize) &&
destination().isEntirelyCovered(dstOffs, rectSize);
}
break;
default:
result = source().isEntirelyCovered(srcOrigin(), size()) &&
destination().isEntirelyCovered(dstOrigin(), size());
break;
}
return result;
}
bool
MapMemoryCommand::isEntireMemory() const
{
return memory().isEntirelyCovered(origin(), size());
}
void
UnmapMemoryCommand::releaseResources()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
//! @todo This is a workaround to a deadlock on indirect map release.
//! Remove this code when CAL will have a refcounter on memory.
//! decIndMapCount() has to go back to submitUnmapMemory()
device::Memory* mem = memory_->getDeviceMemory(queue()->device());
if (NULL != mem) {
mem->releaseIndirectMap();
}
}
OneMemoryArgCommand::releaseResources();
}
bool
MigrateMemObjectsCommand::validateMemory()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
std::vector<amd::Memory*>::const_iterator itr;
for (itr = memObjects_.begin(); itr != memObjects_.end(); itr++) {
device::Memory* mem = (*itr)->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
(*itr)->getSize());
return false;
}
}
}
return true;
}
cl_int
NDRangeKernelCommand::validateMemory()
{
const amd::Device& device = queue()->device();
if (device.info().type_ & CL_DEVICE_TYPE_GPU) {
// Validate the kernel before submission
if (!queue()->device().validateKernel(kernel(), queue()->vdev())) {
return CL_OUT_OF_RESOURCES;
}
const amd::KernelSignature& signature = kernel().signature();
for (uint i = 0; i != signature.numParameters(); ++i) {
const amd::KernelParameterDescriptor& desc = signature.at(i);
// Check if it's a memory object
if ((desc.type_ == T_POINTER) && (desc.size_ != 0)) {
amd::Memory* amdMemory;
if (kernel().parameters().boundToSvmPointer(device,
parameters_,
i)) {
//find the real mem object from svm ptr from the list
amdMemory = amd::SvmManager::FindSvmBuffer(
*reinterpret_cast<void* const*>(parameters() + desc.offset_));
}
else {
amdMemory = *reinterpret_cast<amd::Memory* const*>
(parameters() + desc.offset_);
}
if (amdMemory != NULL) {
if (desc.addressQualifier_ == CL_KERNEL_ARG_ADDRESS_CONSTANT) {
// Make sure argument size isn't bigger than the device limit
if (amdMemory->getSize() > device.info().maxConstantBufferSize_) {
LogPrintfError("HW constant buffer is too big (0x%X bytes)!",
amdMemory->getSize());
return CL_OUT_OF_RESOURCES;
}
}
device::Memory* mem =
amdMemory->getDeviceMemory(device);
if (!kernel().getDeviceKernel(
device)->validateMemory(i, amdMemory)) {
if (device.reallocMemory(*amdMemory)) {
mem = amdMemory->getDeviceMemory(device);
}
else {
mem = NULL;
}
}
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
amdMemory->getSize());
return CL_MEM_OBJECT_ALLOCATION_FAILURE;
}
}
}
}
}
return CL_SUCCESS;
}
bool ExtObjectsCommand::validateMemory()
{
bool retVal = true;
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
for(std::vector<amd::Memory*>::const_iterator itr = memObjects_.begin();
itr != memObjects_.end(); itr++) {
device::Memory* mem = (*itr)->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
(*itr)->getSize());
return false;
}
retVal = processGLResource(mem);
}
}
return retVal;
}
bool AcquireExtObjectsCommand::processGLResource(device::Memory * mem)
{
return mem->processGLResource(device::Memory::GLDecompressResource);
}
bool ReleaseExtObjectsCommand::processGLResource(device::Memory * mem)
{
return mem->processGLResource(device::Memory::GLInvalidateFBO);
}
bool
MakeBuffersResidentCommand::validateMemory()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
for(std::vector<amd::Memory*>::const_iterator itr = memObjects_.begin();
itr != memObjects_.end(); itr++) {
device::Memory* mem = (*itr)->getDeviceMemory(queue()->device());
if (NULL == mem) {
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
(*itr)->getSize());
return false;
}
}
}
return true;
}
bool
ThreadTraceMemObjectsCommand::validateMemory()
{
if (queue()->device().info().type_ & CL_DEVICE_TYPE_GPU) {
for(std::vector<amd::Memory*>::const_iterator itr = memObjects_.begin();
itr != memObjects_.end(); itr++) {
device::Memory* mem = (*itr)->getDeviceMemory(queue()->device());
if (NULL == mem) {
std::vector<amd::Memory*>::const_iterator tmpItr;
for (tmpItr = memObjects_.begin(); tmpItr != itr; tmpItr++) {
device::Memory* tmpMem = (*tmpItr)->getDeviceMemory(queue()->device());
delete tmpMem;
}
LogPrintfError("Can't allocate memory size - 0x%08X bytes!",
(*itr)->getSize());
return false;
}
}
}
return true;
}
} // namespace amd
File diff suppressed because it is too large Load Diff
+197
View File
@@ -0,0 +1,197 @@
//
// Copyright (c) 2012 Advanced Micro Devices, Inc. All rights reserved.
//
#include "commandqueue.hpp"
#include "thread/monitor.hpp"
#include "device/device.hpp"
#include "platform/context.hpp"
/*!
* \file commandQueue.cpp
* \brief Definitions for HostQueue object.
*
* \author Laurent Morichetti (laurent.morichetti@amd.com)
* \date October 2008
*/
namespace amd {
HostQueue::HostQueue(
Context& context, Device& device, cl_command_queue_properties properties
#if cl_amd_open_video
, void* calVideoProperties
#endif // cl_amd_open_video
)
: CommandQueue(context, device, properties, device.info().queueProperties_
| CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD)
#if cl_amd_open_video
, calVideoProperties_(calVideoProperties)
#endif // cl_amd_open_video
{
if (thread_.state() >= Thread::INITIALIZED) {
ScopedLock sl(queueLock_);
thread_.start(this);
queueLock_.wait();
}
}
bool
HostQueue::terminate()
{
if (Os::isThreadAlive(thread_)) {
// Make sure all the commands are finished on the device.
finish();
// Kill the command queue loop.
thread_.acceptingCommands_ = false;
// Wake-up the command loop, so it can exit
flush();
// FIXME_lmoriche: fix termination handshake
while (thread_.state() < Thread::FINISHED) {
Os::yield();
}
}
if (Agent::shouldPostCommandQueueEvents()) {
Agent::postCommandQueueFree(as_cl(this->asCommandQueue()));
}
return true;
}
void
HostQueue::finish()
{
// Send a finish to make sure we finished all commands
Command* command = new Marker(*this, false);
if (command == NULL) {
return;
}
command->enqueue();
command->awaitCompletion();
command->release();
}
void
HostQueue::loop(device::VirtualDevice* virtualDevice)
{
cl_int (CL_CALLBACK * commandIntercept)(cl_event, cl_int *) =
properties().test(CL_QUEUE_COMMAND_INTERCEPT_ENABLE_AMD)
? context().info().commandIntercept_ : NULL;
// Notify the caller that the queue is ready to accept commands.
{
ScopedLock sl(queueLock_);
thread_.acceptingCommands_ = true;
queueLock_.notify();
}
// Create a command batch with all the commands present in the queue.
Command* head = NULL;
Command* tail = NULL;
while (true) {
// Get one command from the queue
Command* command = queue_.dequeue();
if (command == NULL) {
ScopedLock sl(queueLock_);
while ((command = queue_.dequeue()) == NULL) {
if (!thread_.acceptingCommands_) {
return;
}
queueLock_.wait();
}
}
command->retain();
// Process the command's event wait list.
const Command::EventWaitList& events = command->eventWaitList();
Command::EventWaitList::const_iterator it;
bool dependencyFailed = false;
for (it = events.begin(); it != events.end(); ++it) {
// Only wait if the command is enqueued into another queue.
if ((*it)->command().queue() != this) {
virtualDevice->flush(head, true);
tail = head = NULL;
dependencyFailed |= !(*it)->awaitCompletion();
}
}
// Insert the command to the linked list.
if (NULL == head) { //if the list is empty
head = tail = command;
}
else {
tail->setNext(command);
tail = command;
}
if (dependencyFailed) {
command->setStatus(CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST);
continue;
}
command->setStatus(CL_SUBMITTED);
cl_int result;
if ((commandIntercept != NULL) &&
commandIntercept(as_cl<Event>(command), &result)) {
// The command was handled by the callback.
command->setStatus(CL_RUNNING, command->profilingInfo().submitted_);
command->setStatus(result);
continue;
}
// Submit to the device queue.
command->submit(*virtualDevice);
//if we are in intercept mode or this is a user invisible marker command
if ((0 == command->type()) || (commandIntercept != NULL)) {
virtualDevice->flush(head);
tail = head = NULL;
}
} // while (true) {
}
void
HostQueue::append(Command& command)
{
// We retain the command here. It will be released when its status
// changes to CL_COMPLETE
command.retain();
command.setStatus(CL_QUEUED);
queue_.enqueue(&command);
}
DeviceQueue::~DeviceQueue()
{
delete virtualDevice_;
ScopedLock lock(context().lock());
context().removeDeviceQueue(device(), this);
}
bool
DeviceQueue::create()
{
static const bool InteropQueue = true;
const bool defaultDeviceQueue = properties().test(CL_QUEUE_ON_DEVICE_DEFAULT);
bool result = false;
virtualDevice_ = device().createVirtualDevice(
properties().test(CL_QUEUE_PROFILING_ENABLE),
!InteropQueue, NULL, size_);
if (virtualDevice_ != NULL) {
result = true;
context().addDeviceQueue(device(), this, defaultDeviceQueue);
}
return result;
}
} //namespace amd {
+254
View File
@@ -0,0 +1,254 @@
//
// Copyright 2012 Advanced Micro Devices, Inc. All rights reserved.
//
/*! \file commandqueue.hpp
* \brief Declarations CommandQueue object.
*
* \author Laurent Morichetti (laurent.morichetti@amd.com)
* \date October 2008
*/
#ifndef COMMAND_QUEUE_HPP_
#define COMMAND_QUEUE_HPP_
#include "thread/thread.hpp"
#include "platform/object.hpp"
#include "platform/command.hpp"
/*! \brief Holds commands that will be executed on a specific device.
*
* \details A command queue is created on a specific device in
* a Context. A new virtual device will be instantiated from the given
* device and an execution environment (a thread) will be created to run
* the CommandQueue::loop() function.
*/
namespace amd {
class HostQueue;
class DeviceQueue;
class CommandQueue : public RuntimeObject
{
public:
struct Properties
{
typedef cl_command_queue_properties value_type;
const value_type mask_;
value_type value_;
Properties(value_type mask, value_type value) :
mask_(mask), value_(value & mask)
{ }
bool set(value_type bits) {
if ((mask_ & bits) != bits) {
return false;
}
value_ |= bits;
return true;
}
bool clear(value_type bits) {
if ((mask_ & bits) != bits) {
return false;
}
value_ &= ~bits;
return true;
}
bool test(value_type bits) const {
return (value_ & bits) != 0;
}
};
//! Return the context this command queue is part of.
Context& context() const { return context_(); }
//! Return the device for this command queue.
Device& device() const { return device_; }
//! Return the command queue properties.
Properties properties() const { return properties_; }
Properties& properties() { return properties_; }
//! Returns the base class object
CommandQueue* asCommandQueue() { return this; }
virtual ~CommandQueue() {}
//! Returns TRUE if the object was successfully created
virtual bool create() = 0;
//! RTTI internal implementation
virtual ObjectType objectType() const { return ObjectTypeQueue; }
//! Rturns HostQueue object
virtual HostQueue* asHostQueue() { return NULL; }
//! Returns DeviceQueue object
virtual DeviceQueue* asDeviceQueue() { return NULL; }
protected:
//! CommandQueue constructor is protected
//! to keep the CommandQueue class as a virtual interface
CommandQueue(
Context& context, //!< Context object
Device& device, //!< Device object
cl_command_queue_properties properties, //!< Queue properties
cl_command_queue_properties propMask //!< Queue properties mask
)
: properties_(propMask, properties)
, queueLock_("CommandQueue::queueLock")
, device_(device)
, context_(context) {}
Properties properties_; //!< Queue properties
Monitor queueLock_; //!< Lock protecting the queue
Device& device_; //!< The device
SharedReference<Context> context_; //!< The context of this command queue
private:
//! Disable copy constructor
CommandQueue(const CommandQueue&);
//! Disable assignment
CommandQueue& operator=(const CommandQueue&);
};
class HostQueue : public CommandQueue
{
class Thread : public amd::Thread
{
public:
//! True if this command queue thread is accepting commands.
volatile bool acceptingCommands_;
//! Create a new thread
Thread() : amd::Thread("Command Queue Thread", CQ_THREAD_STACK_SIZE),
acceptingCommands_(false), virtualDevice_(NULL)
{ }
//! The command queue thread entry point.
void run(void *data) {
HostQueue* queue = static_cast<HostQueue*>(data);
bool interopQueue = (0 != (queue->context().info().flags_ & (Context::GLDeviceKhr | Context::D3D10DeviceKhr | Context::D3D11DeviceKhr)));
virtualDevice_ = queue->device().createVirtualDevice(
queue->properties().test(CL_QUEUE_PROFILING_ENABLE),
interopQueue
#if cl_amd_open_video
, queue->calVideoProperties_
#endif // cl_amd_open_video
);
if (virtualDevice_ != NULL) {
queue->loop(virtualDevice_);
if (virtualDevice_->terminate()) {
delete virtualDevice_;
}
}
else {
acceptingCommands_ = false;
queue->flush();
}
}
//! Get virtual device for the current thread
const device::VirtualDevice* vdev() const { return virtualDevice_; }
private:
device::VirtualDevice* virtualDevice_; //!< Virtual device for this thread
} thread_; //!< The command queue thread instance.
private:
ConcurrentLinkedQueue<Command*> queue_; //!< The queue.
//! Await commands and execute them as they become ready.
void loop(device::VirtualDevice* virtualDevice);
protected:
virtual bool terminate();
#if cl_amd_open_video
void* calVideoProperties_;
#endif // cl_amd_open_video
public:
/*! \brief Construct a new host queue.
*
* \note A new virtual device instance will be created from the
* given device.
*/
HostQueue(
Context& context,
Device& device,
cl_command_queue_properties properties
#if cl_amd_open_video
, void* calVideoProperties = NULL
#endif // cl_amd_open_video
);
//! Returns TRUE if this command queue can accept commands.
virtual bool create() { return thread_.acceptingCommands_; }
//! Append the given command to the queue.
void append(Command& command);
//! Return the thread object running the command loop.
const Thread& thread() const { return thread_; }
//! Signal to start processing the commands in the queue.
void flush () { ScopedLock sl(queueLock_); queueLock_.notify(); }
//! Finish all queued commands
void finish();
//! Get virtual device for the current command queue
const device::VirtualDevice* vdev() const { return thread_.vdev(); }
//! Return the current queue as the HostQueue
virtual HostQueue* asHostQueue() { return this; }
};
class DeviceQueue : public CommandQueue
{
public:
DeviceQueue(
Context& context, //!< Context object
Device& device, //!< Device object
cl_command_queue_properties properties, //!< Queue properties
uint size //!< Device queue size
)
: CommandQueue(context, device, properties, device.info().queueOnDeviceProperties_
| CL_QUEUE_ON_DEVICE | CL_QUEUE_ON_DEVICE_DEFAULT)
, size_(size)
, virtualDevice_(NULL) {}
virtual ~DeviceQueue();
//! Returns TRUE if device queue was successfully created
virtual bool create();
//! Return the current queue as the DeviceQueue
virtual DeviceQueue* asDeviceQueue() { return this; }
//! Returns the size of device queue
uint size() const { return size_; }
//! Returns virtual device for this device queue
device::VirtualDevice* vDev() const { return virtualDevice_; }
//! Returns the queue lock
Monitor& lock() { return queueLock_; }
private:
uint size_; //!< Device queue size
device::VirtualDevice* virtualDevice_; //!< Virtual device for this queue
};
} //namespace amd
#endif //COMMAND_QUEUE_HPP_
+363
View File
@@ -0,0 +1,363 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/context.hpp"
#include "amdocl/cl_gl_amd.hpp"
#include "amdocl/cl_common.hpp"
#include "platform/commandqueue.hpp"
#include <algorithm>
#include <functional>
#ifdef _WIN32
#include <d3d10_1.h>
#include <dxgi.h>
#include "CL/cl_d3d10.h"
#include "CL/cl_d3d11.h"
#include "CL/cl_dx9_media_sharing.h"
#endif //_WIN32
namespace amd {
Context::Context(
const std::vector<Device*>& devices,
const Info& info)
: devices_(devices)
, info_(info)
, properties_(NULL)
, glenv_(NULL)
, customHostAllocDevice_(NULL)
, customSvmAllocDevice_(NULL)
{
for (std::vector<Device *>::const_iterator it = devices_.begin();
it != devices_.end(); it++) {
Device* device = *it;
device->retain();
if (device->customHostAllocator()) {
assert(!customHostAllocDevice_ && "Only one custom host allocator "
"is allowed per context");
customHostAllocDevice_ = device;
}
if (device->customSvmAllocator()) {
customSvmAllocDevice_ = device;
}
}
}
Context::~Context()
{
static const bool VALIDATE_ONLY = false;
// Dissociate OCL context with any external device
if (info_.flags_ & (GLDeviceKhr | D3D10DeviceKhr | D3D11DeviceKhr)) {
std::vector<Device *>::const_iterator it;
// Loop through all devices
for (it = devices_.begin(); it != devices_.end(); it++) {
(*it)->unbindExternalDevice(info_.type_, info_.hDev_, info_.hCtx_, VALIDATE_ONLY);
}
}
if (properties_ != NULL) {
delete [] properties_;
}
if (glenv_ != NULL) {
delete glenv_;
glenv_ = NULL;
}
std::for_each(devices_.begin(), devices_.end(),
std::mem_fun(&Device::release));
}
int
Context::checkProperties(
const cl_context_properties* properties,
Context::Info* info)
{
cl_platform_id pfmId = 0;
uint count = 0;
const struct Element
{
intptr_t name;
void* ptr;
} *p = reinterpret_cast<const Element*>(properties);
// Clear the context infor structure
::memset(info, 0, sizeof(Context::Info));
if (properties == NULL) {
return CL_SUCCESS;
}
// Process all properties
while (p->name != 0) {
switch (p->name) {
case CL_CONTEXT_INTEROP_USER_SYNC:
if (p->ptr == reinterpret_cast<void*>(CL_TRUE))
{
info->flags_ |= InteropUserSync;
}
break;
#ifdef _WIN32
case CL_CONTEXT_D3D10_DEVICE_KHR:
if (p->ptr == NULL) {
return CL_INVALID_VALUE;
}
info->hDev_ = p->ptr;
info->type_ = CL_CONTEXT_D3D10_DEVICE_KHR;
info->flags_ |= D3D10DeviceKhr;
break;
case CL_CONTEXT_D3D11_DEVICE_KHR:
if (p->ptr == NULL) {
return CL_INVALID_VALUE;
}
info->hDev_ = p->ptr;
info->type_ = CL_CONTEXT_D3D11_DEVICE_KHR;
info->flags_ |= D3D11DeviceKhr;
break;
case CL_CONTEXT_ADAPTER_D3D9_KHR:
if (p->ptr == NULL) { //not supported for xp
return CL_INVALID_VALUE;
}
info->hDev_ = p->ptr;
info->type_ = CL_CONTEXT_ADAPTER_D3D9_KHR;
info->flags_ |= D3D9DeviceKhr;
break;
case CL_CONTEXT_ADAPTER_D3D9EX_KHR:
if (p->ptr == NULL) {
return CL_INVALID_VALUE;
}
info->hDev_ = p->ptr;
info->type_ = CL_CONTEXT_ADAPTER_D3D9EX_KHR;
info->flags_ |= D3D9DeviceEXKhr;
break;
case CL_CONTEXT_ADAPTER_DXVA_KHR:
if (p->ptr == NULL) {
return CL_INVALID_VALUE;
}
info->hDev_ = p->ptr;
info->type_ = CL_CONTEXT_ADAPTER_DXVA_KHR;
info->flags_ |= D3D9DeviceVAKhr;
break;
case CL_WGL_HDC_KHR:
info->hDev_ = p->ptr;
#endif //_WIN32
#if defined(__linux__)
case CL_GLX_DISPLAY_KHR:
info->hDev_ = p->ptr;
#endif //linux
#if defined(__APPLE__) || defined(__MACOSX)
case CL_CGL_SHAREGROUP_KHR:
Unimplemented();
break;
#endif //__APPLE__ || MACOS
case CL_GL_CONTEXT_KHR:
if (p->ptr == NULL) {
return CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR;
}
if (p->name == CL_GL_CONTEXT_KHR) {
info->type_ = p->name;
info->hCtx_ = p->ptr;
}
info->flags_ |= GLDeviceKhr;
break;
case CL_CONTEXT_PLATFORM:
pfmId = reinterpret_cast<cl_platform_id>(p->ptr);
if ((NULL != pfmId) && (AMD_PLATFORM != pfmId)) {
return CL_INVALID_VALUE;
}
break;
case CL_CONTEXT_OFFLINE_DEVICES_AMD:
if (p->ptr != reinterpret_cast<void*>(1)) {
return CL_INVALID_VALUE;
}
// Set the offline device flag
info->flags_ |= OfflineDevices;
break;
case CL_CONTEXT_COMMAND_INTERCEPT_CALLBACK_AMD:
// Set the command intercept flag
info->commandIntercept_ =
(cl_int (CL_CALLBACK *)(cl_event, cl_int *)) p->ptr;
info->flags_ |= CommandIntercept;
break;
default:
return CL_INVALID_VALUE;
}
p++;
count++;
}
info->propertiesSize_ = count * sizeof(Element) + sizeof(intptr_t);
return CL_SUCCESS;
}
int
Context::create(const intptr_t* properties)
{
static const bool VALIDATE_ONLY = false;
int result = CL_SUCCESS;
if (properties != NULL) {
properties_ = new cl_context_properties[
info().propertiesSize_ / sizeof(cl_context_properties)];
if (properties_ == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
::memcpy(properties_, properties, info().propertiesSize_);
}
// Check if OCL context can be associated with any external device
if (info_.flags_ & (D3D10DeviceKhr | D3D11DeviceKhr | GLDeviceKhr |
D3D9DeviceKhr | D3D9DeviceEXKhr | D3D9DeviceVAKhr)) {
std::vector<Device *>::const_iterator it;
// Loop through all devices
for (it = devices_.begin(); it != devices_.end(); it++) {
if (!(*it)->bindExternalDevice(
info_.type_, info_.hDev_, info_.hCtx_, VALIDATE_ONLY)) {
result = CL_INVALID_VALUE;
}
}
}
// Check if the device binding wasn't successful
if (result != CL_SUCCESS) {
if (info_.flags_ & GLDeviceKhr) {
result = CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR;
}
else if (info_.flags_ & D3D10DeviceKhr) {
//return CL_INVALID_VALUE; // FIXME_odintsov: CL_INVALID_D3D_INTEROP;
}
else if (info_.flags_ & D3D11DeviceKhr) {
//return CL_INVALID_VALUE; // FIXME_odintsov: CL_INVALID_D3D_INTEROP;
}
else if (info_.flags_ & (D3D9DeviceKhr | D3D9DeviceEXKhr | D3D9DeviceVAKhr)) {
//return CL_INVALID_DX9_MEDIA_ADAPTER_KHR;
}
}
else {
if (info_.flags_ & GLDeviceKhr) {
// Init context for GL interop
if(glenv_ == NULL) {
HMODULE h = (HMODULE) Os::loadLibrary(
#ifdef _WIN32
"OpenGL32.dll"
#else //!_WIN32
"libGL.so"
#endif //!_WIN32
);
if (h && (glenv_ = new GLFunctions(h))) {
if (!glenv_->init(reinterpret_cast<intptr_t>(info_.hDev_),
reinterpret_cast<intptr_t>(info_.hCtx_))) {
delete glenv_;
glenv_ = NULL;
result = CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR;
}
}
}
}
}
return result;
}
void*
Context::hostAlloc(size_t size, size_t alignment, bool atomics) const
{
if (customHostAllocDevice_ != NULL) {
return customHostAllocDevice_->hostAlloc(size, alignment, atomics);
}
return AlignedMemory::allocate(size, alignment);
}
void
Context::hostFree(void* ptr) const
{
if (customHostAllocDevice_ != NULL) {
customHostAllocDevice_->hostFree(ptr);
return;
}
AlignedMemory::deallocate(ptr);
}
void*
Context::svmAlloc(size_t size, size_t alignment, cl_svm_mem_flags flags)
{
if (customSvmAllocDevice_ != NULL) {
return customSvmAllocDevice_->svmAlloc(*this, size, alignment, flags);
}
return AlignedMemory::allocate(size, alignment);
}
void
Context::svmFree(void* ptr) const
{
if (customSvmAllocDevice_ != NULL) {
customSvmAllocDevice_->svmFree(ptr);
return;
}
AlignedMemory::deallocate(ptr);
}
bool
Context::containsDevice(const Device* device) const
{
std::vector<Device *>::const_iterator it;
for (it = devices_.begin(); it != devices_.end(); ++it) {
if (device == *it || (*it)->isAncestor(device)) {
return true;
}
}
return false;
}
DeviceQueue*
Context::defDeviceQueue(const Device& dev) const
{
std::map<const Device*, DeviceQueueInfo>::const_iterator it =
deviceQueues_.find(&dev);
if (it != deviceQueues_.end()) {
return it->second.defDeviceQueue_;
}
else {
return NULL;
}
}
bool
Context::isDevQueuePossible(const Device& dev)
{
return (deviceQueues_[&dev].deviceQueueCnt_ < dev.info().maxOnDeviceQueues_) ?
true : false;
}
void
Context::addDeviceQueue(const Device& dev, DeviceQueue* queue, bool defDevQueue)
{
DeviceQueueInfo& info = deviceQueues_[&dev];
info.deviceQueueCnt_++;
if (defDevQueue) {
info.defDeviceQueue_ = queue;
}
}
void
Context::removeDeviceQueue(const Device& dev, DeviceQueue* queue)
{
DeviceQueueInfo& info = deviceQueues_[&dev];
assert((info.deviceQueueCnt_ != 0) && "The device queue map is empty!");
info.deviceQueueCnt_--;
if (info.defDeviceQueue_ == queue) {
info.defDeviceQueue_ = NULL;
}
}
} // namespace amd
+198
View File
@@ -0,0 +1,198 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef CONTEXT_HPP_
#define CONTEXT_HPP_
#include "top.hpp"
#include "device/device.hpp"
#include "platform/object.hpp"
#include "platform/agent.hpp"
#include <vector>
#include <map>
namespace amd {
/*! \addtogroup Runtime
* @{
*
* \addtogroup Contexts
* @{
*/
class GLFunctions;
class DeviceQueue;
class Context : public RuntimeObject
{
std::vector<Device*> devices_;
public:
enum Flags
{
GLDeviceKhr = 1<<0, //!< GL
D3D10DeviceKhr = 1<<1, //!< D3D10
OfflineDevices = 1<<2, //!< Offline devices
CommandIntercept = 1<<3, //!< Command intercept
D3D11DeviceKhr = 1<<4, //!< D3D11
InteropUserSync = 1<<5, //!< Interop user sync enabled
D3D9DeviceKhr = 1<<6, //!< d3d9 device
D3D9DeviceEXKhr = 1<<7, //!< d3d9EX device
D3D9DeviceVAKhr = 1<<8, //!< d3d9VA device
};
//! Context info structure
struct Info
{
uint flags_; //!< Context info flags
intptr_t type_; //!< Context type
void* hDev_; //!< Device object reference
void* hCtx_; //!< Context object reference
size_t propertiesSize_;//!< Size of the original properties in bytes
cl_int (CL_CALLBACK * commandIntercept_)(cl_event, cl_int *);
};
struct DeviceQueueInfo
{
DeviceQueue* defDeviceQueue_; //!< Default device queue
uint deviceQueueCnt_; //!< The number of device queues
DeviceQueueInfo(): defDeviceQueue_(NULL), deviceQueueCnt_(0) {}
};
private:
// Copying a Context is not allowed
Context(const Context&);
Context& operator = (const Context&);
protected:
bool terminate() {
if (Agent::shouldPostContextEvents()) {
Agent::postContextFree(as_cl(this));
}
return true;
}
//! Context destructor
~Context();
public:
/*! \brief Helper function to check the context properties and initialize
* context info structure
*
* \return An errcode if invalid, CL_SUCCESS if valid
*/
static int checkProperties(
const cl_context_properties* properties, //!< Properties
Info* info //!< Info structure
);
//! Default constructor
Context(
const std::vector<Device*>& devices, //!< List of all devices
const Info& info //!< Context info structure
);
//! Compare two Context instances.
bool operator == (const Context& rhs) const { return this == &rhs; }
bool operator != (const Context& rhs) const { return !(*this == rhs); }
/*! Creates the context
*
* \return An errcode if runtime fails the context creation,
* CL_SUCCESS otherwise
*/
int create(
const intptr_t* properties //!< Original context properties
);
/**
* Allocate host memory using either a custom device allocator or a generic
* OS allocator
*
* @param size Allocation size, in bytes
* @param alignment Desired alignment, in bytes
* @param atomics The buffer should support platform (SVM) atomics
*/
void* hostAlloc(size_t size, size_t alignment, bool atomics = false) const;
/**
* Release host memory
* @param ptr Pointer allocated using ::hostAlloc. If the pointer has been
* allocated elsewhere, the behavior is undefined
*/
void hostFree(void* ptr) const;
/**
* Allocate SVM buffer
*
* @param size Allocation size, in bytes
* @param alignment Desired alignment, in bytes
* @param flags The flags to create a svm space
*/
void* svmAlloc(size_t size, size_t alignment, cl_svm_mem_flags flags = CL_MEM_READ_WRITE);
/**
* Release SVM buffer
* @param ptr Pointer allocated using ::svmAlloc. If the pointer has been
* allocated elsewhere, the behavior is undefined
*/
void svmFree(void* ptr) const;
//! Return the devices associated with this context.
const std::vector<Device*>& devices() const { return devices_; }
//! Returns true if the given device is associated with this context.
bool containsDevice(const Device* device) const;
//! Returns the context info structure
const Info& info() const { return info_; }
//! Returns a pointer to the original properties
const cl_context_properties* properties() const { return properties_; }
//! Returns a pointer to the OpenGL context
GLFunctions* glenv() const { return glenv_; }
//! RTTI internal implementation
virtual ObjectType objectType() const { return ObjectTypeContext; }
//! Returns context lock for the serialized access to the context
Monitor& lock() { return ctxLock_; }
//! Returns TRUE if runtime succesfully added a device queue
DeviceQueue* defDeviceQueue(const Device& dev) const;
//! Returns TRUE if runtime succesfully added a device queue
bool isDevQueuePossible(const Device& dev);
//! Returns TRUE if runtime succesfully added a device queue
void addDeviceQueue(
const Device& dev, //!< Device object
DeviceQueue* queue, //!< Device queue
bool defDevQueue //!< Added device queue will be the default queue
);
//! Removes a device queue from the list of queues
void removeDeviceQueue(
const Device& dev, //!< Device object
DeviceQueue* queue //!< Device queue
);
private:
const Info info_; //!< Context info structure
cl_context_properties* properties_; //!< Original properties
GLFunctions* glenv_; //!< OpenGL context
Device* customHostAllocDevice_; //!< Device responsible for host allocations
Device* customSvmAllocDevice_; //!< Device responsible for SVM allocations
std::map<const Device*, DeviceQueueInfo> deviceQueues_; //!< Device queues mapping
Monitor ctxLock_; //!< Lock for the context access
};
/*! @}
* @}
*/
} // namespace amd
#endif /*CONTEXT_HPP_*/
+33
View File
@@ -0,0 +1,33 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef COUNTERS_HPP_
#define COUNTERS_HPP_
#include "top.hpp"
namespace amd {
/*! \addtogroup Runtime
* @{
*
* \addtogroup Devicecounter
* @{
*/
/*! \class Counter
*
* \brief The container class for the performance counters
*/
class Counter : public RuntimeObject
{
public:
//! RTTI internal implementation
virtual ObjectType objectType() const {return ObjectTypeCounter;}
};
/*@}*/
/*@}*/ } // namespace amd
#endif // COUNTERS_HPP_
+50
View File
@@ -0,0 +1,50 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef INTEROP_H_
#define INTEROP_H_
namespace amd {
//! Forward declarations of interop classes
class GLObject;
class BufferGL;
#ifdef _WIN32
class D3D10Object;
class D3D11Object;
class D3D9Object;
#endif //_WIN32
//! Base object providing common map/unmap interface for interop objects
class InteropObject
{
public:
//! Virtual destructor to get rid of linux warning
virtual ~InteropObject() {}
// Static cast functions for interop objects
virtual GLObject* asGLObject() { return NULL; }
virtual BufferGL* asBufferGL() { return NULL; }
#ifdef _WIN32
virtual D3D10Object* asD3D10Object() { return NULL; }
virtual D3D11Object* asD3D11Object() { return NULL; }
virtual D3D9Object* asD3D9Object() { return NULL; }
#endif //_WIN32
// On acquire copy data from original resource to shared resource
virtual bool copyOrigToShared() { return true; }
// On release copy data from shared copy to the original resource
virtual bool copySharedToOrig() { return true; }
//! Mapping functions for interop objects
virtual bool mapExtObjectInCQThread() { return true; }
virtual bool unmapExtObjectInCQThread() { return true; }
};
} // namespace amd
#endif //!INTEROP_H_
+254
View File
@@ -0,0 +1,254 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/kernel.hpp"
#include "platform/program.hpp"
#include "os/alloc.hpp"
#include "platform/command.hpp"
#include "platform/commandqueue.hpp"
#include "platform/sampler.hpp"
namespace amd {
Kernel::Kernel(Program& program, const Symbol& symbol, const std::string& name)
: program_(program), symbol_(symbol), name_(name)
{
const KernelSignature& s = signature();
size_t stackSize = s.paramsSize();
parameters_ = new (s) KernelParameters(s);
fixme_guarantee(parameters_ != NULL && "out of memory");
name_ += '\0';
}
Kernel::~Kernel()
{
// Release kernel object itself
delete parameters_;
}
const device::Kernel*
Kernel::getDeviceKernel(const Device& device, bool noAlias) const
{
return symbol_.getDeviceKernel(device, noAlias);
}
const KernelSignature&
Kernel::signature() const
{
return symbol_.signature();
}
bool
KernelParameters::check()
{
if (validated_) {
return true;
}
for (size_t i = 0; i < signature_.numParameters(); ++i) {
if (!test(i)) {
return false;
}
}
validated_ = true;
return true;
}
size_t
KernelParameters::localMemSize(size_t minDataTypeAlignment) const
{
size_t memSize = 0;
for (size_t i = 0; i < signature_.numParameters(); ++i) {
const KernelParameterDescriptor& desc = signature_.at(i);
if (desc.size_ == 0) {
memSize = alignUp(memSize, minDataTypeAlignment)
+ *reinterpret_cast<const size_t*>(values_ + desc.offset_);
}
}
return memSize;
}
void
KernelParameters::set(
size_t index,
size_t size,
const void* value,
bool svmBound)
{
const KernelParameterDescriptor& desc = signature_.at(index);
void* param = values_ + desc.offset_;
assert((desc.type_ == T_POINTER || value != NULL || desc.size_ == 0) &&
"not a valid local mem arg");
uint32_t uint32_value = 0;
uint64_t uint64_value = 0;
if (desc.type_ == T_POINTER && desc.size_ != 0) {
if (svmBound) {
LP64_SWITCH(uint32_value, uint64_value) =
(LP64_SWITCH(uint32_t, uint64_t)) value;
svmBound_[index] = true;
}
else if ((value == NULL) || (static_cast<const cl_mem*>(value) == NULL)) {
LP64_SWITCH(uint32_value, uint64_value) = 0;
}
else {
// convert cl_mem to amd::Memory*
LP64_SWITCH(uint32_value, uint64_value) =
(uintptr_t) as_amd(*static_cast<const cl_mem*>(value));
}
}
else if (desc.type_ == T_SAMPLER) {
// convert cl_sampler to amd::Sampler*
amd::Sampler *sampler = as_amd(*static_cast<const cl_sampler*>(value));
LP64_SWITCH(uint32_value, uint64_value) = (uintptr_t) sampler;
}
else if (desc.type_ == T_QUEUE) {
// convert cl_command_queue to amd::DeviceQueue*
amd::DeviceQueue* queue =
as_amd(*static_cast<const cl_command_queue*>(value))->asDeviceQueue();
LP64_SWITCH(uint32_value, uint64_value) = (uintptr_t) queue;
}
else switch (desc.size_) {
case 1: uint32_value = *static_cast<const uint8_t*>(value); break;
case 2: uint32_value = *static_cast<const uint16_t*>(value); break;
case 4: uint32_value = *static_cast<const uint32_t*>(value); break;
case 8: uint64_value = *static_cast<const uint64_t*>(value); break;
default: break;
}
switch (desc.size_) {
case 0 /*local mem*/ : *static_cast<size_t*>(param) = size; break;
case sizeof(uint32_t): *static_cast<uint32_t*>(param) = uint32_value; break;
case sizeof(uint64_t): *static_cast<uint64_t*>(param) = uint64_value; break;
default: ::memcpy(param, value, size); break;
}
defined_[index] = true;
}
address
KernelParameters::capture(const Device& device)
{
const size_t stackSize = signature_.paramsSize();
//! Information about which arguments are SVM pointers is stored after
// the actual parameters, but only if the device has any SVM capability
const size_t svmInfoSize = device.info().svmCapabilities_ ?
signature_.numParameters() * sizeof(bool) : 0;
const size_t execInfoSize = getNumberOfSvmPtr() * sizeof(void*);
address mem = (address) AlignedMemory::allocate(
stackSize + svmInfoSize + execInfoSize, PARAMETERS_MIN_ALIGNMENT);
address last = mem + stackSize;
if (mem != NULL) {
::memcpy(mem, values_, stackSize);
for (size_t i = 0; i < signature_.numParameters(); ++i) {
const KernelParameterDescriptor& desc = signature_.at(i);
if (desc.type_ == T_POINTER && desc.size_ != 0 && !svmBound_[i]) {
Memory* memArg = *(Memory**)(mem + desc.offset_);
if (memArg != NULL) {
memArg->retain();
}
}
else if (desc.type_ == T_SAMPLER) {
// We're going to replace (mem + desc.offset_) in the
// CPU device code -- It will go from Sampler* to clk_sampler.
// Do the retain() and release() on this other copy.
Sampler* samplerArg = *(Sampler**)(values_ + desc.offset_);
if (samplerArg != NULL) {
samplerArg->retain();
}
}
else if (desc.type_ == T_QUEUE) {
DeviceQueue* queue = *(DeviceQueue**)(values_ + desc.offset_);
if (queue != NULL) {
queue->retain();
}
}
}
::memcpy(last, svmBound_, svmInfoSize);
last += svmInfoSize;
if (0 != execInfoSize) {
::memcpy(last, &execSvmPtr_[0], execInfoSize);
}
execInfoOffset_ = stackSize + svmInfoSize;
}
return mem;
}
bool
KernelParameters::boundToSvmPointer(const Device& device,
const_address capturedParameter,
size_t index) const
{
if (!device.info().svmCapabilities_) {
return false;
}
//! Information about which arguments are SVM pointers is stored after
// actual parameters
const bool* svmBound = reinterpret_cast<const bool*>(capturedParameter +
signature_.paramsSize());
return svmBound[index];
}
void
KernelParameters::release(address mem, const amd::Device& device) const
{
if (mem == NULL) {
// nothing to do!
return;
}
for (size_t i = 0; i < signature_.numParameters(); ++i) {
const KernelParameterDescriptor& desc = signature_.at(i);
if (desc.type_ == T_POINTER && desc.size_ != 0 &&
!boundToSvmPointer(device, mem, i)) {
Memory* memArg = *(Memory**)(mem + desc.offset_);
if (memArg != NULL) {
memArg->release();
}
}
else if (desc.type_ == T_SAMPLER) {
Sampler* samplerArg = *(Sampler**)(values_ + desc.offset_);
if (samplerArg != NULL) {
samplerArg->release();
}
}
else if (desc.type_ == T_QUEUE) {
DeviceQueue* queue = *(DeviceQueue**)(values_ + desc.offset_);
if (queue != NULL) {
queue->release();
}
}
}
AlignedMemory::deallocate(mem);
}
KernelSignature::KernelSignature(
const std::vector<KernelParameterDescriptor>& params,
const std::string& attrib)
: params_(params), paramsSize_(0)
, attributes_(attrib)
{
if (params.size() > 0) {
KernelParameterDescriptor last = params.back();
size_t lastSize = last.size_;
if (lastSize == 0 /* local mem */) {
lastSize = sizeof(cl_mem);
}
paramsSize_ = last.offset_ + alignUp(lastSize, sizeof(intptr_t));
}
}
} // namespace amd
+221
View File
@@ -0,0 +1,221 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef KERNEL_HPP_
#define KERNEL_HPP_
#include "top.hpp"
#include "platform/object.hpp"
#include "amdocl/cl_kernel.h"
#include <vector>
#include <cstdlib> // for malloc
#include <string>
#include "device/device.hpp"
enum FGSStatus {
FGS_DEFAULT, //!< The default kernel fine-grained system pointer support
FGS_NO, //!< no support of kernel fine-grained system pointer
FGS_YES //!< have support of kernel fine-grained system pointer
};
namespace amd {
class Symbol;
class Program;
/*! \addtogroup Runtime
* @{
*
* \addtogroup Program Programs and Kernel functions
* @{
*/
class KernelSignature : public HeapObject
{
private:
std::vector<KernelParameterDescriptor> params_;
size_t paramsSize_;
std::string attributes_; //!< The kernel attributes
public:
//! Default constructor
KernelSignature() : paramsSize_(0) { }
//! Construct a new signature.
KernelSignature(
const std::vector<KernelParameterDescriptor>& params,
const std::string& attrib
);
//! Return the number of parameters
size_t numParameters() const { return params_.size(); }
//! Return the parameter descriptor at the given index.
const KernelParameterDescriptor& at(size_t index) const
{
assert(index < params_.size() && "index is out of bounds");
return params_[index];
}
//! Return the size in bytes required for the arguments on the stack.
size_t paramsSize() const { return paramsSize_; }
//! Return the kernel attributes
const std::string& attributes() const { return attributes_; }
};
// @todo: look into a copy-on-write model instead of copy-on-read.
//
class KernelParameters : protected HeapObject
{
private:
//! The signature describing these parameters.
const KernelSignature& signature_;
address values_; //!< pointer to the base of the values stack.
bool* defined_; //!< pointer to the isDefined flags.
bool validated_; //!< True if all parameters are defined.
bool* svmBound_; //!< True at 'i' if parameter 'i' is bound to SVM pointer
size_t execInfoOffset_; //!< The offset of execInfo
std::vector<void*> execSvmPtr_; //!< The non argument svm pointers for kernel
FGSStatus svmSystemPointersSupport_; //!< The flag for the status of the kernel
// support of fine-grain system sharing.
public:
//! Construct a new instance of parameters for the given signature.
KernelParameters(const KernelSignature& signature) :
signature_(signature), validated_(false), execInfoOffset_(0), svmSystemPointersSupport_(FGS_DEFAULT)
{
values_ = (address) this + alignUp(sizeof(KernelParameters), 16);
defined_ = (bool*) (values_ + signature.paramsSize());
svmBound_ = (bool*) ((address) defined_ + signature.numParameters() * sizeof(bool));
address limit = (address) &svmBound_[signature.numParameters()];
::memset(values_, '\0', limit - values_);
}
//! Reset the parameter at the given \a index (becomes undefined).
void reset(size_t index)
{
defined_[index] = false;
svmBound_[index] = false;
validated_ = false;
}
//! Set the parameter at the given \a index to the value pointed by \a value
// \a svmBound indicates that \a value is a SVM pointer.
void set(size_t index, size_t size, const void* value, bool svmBound = false);
//! Return true if the parameter at the given \a index is defined.
bool test(size_t index) const { return defined_[index]; }
//! Return true if all the parameters have been defined.
bool check();
//! The amount of memory required for local memory needed
size_t localMemSize(size_t minDataTypeAlignment) const;
//! Capture the state of the parameters and return the stack base pointer.
address capture(const Device& device);
//! Release the captured state of the parameters.
void release(address parameters, const amd::Device& device) const;
//! Allocate memory for this instance as well as the required storage for
// the values_, defined_, and svmBound_ arrays.
void* operator new(size_t size, const KernelSignature& signature)
{
size_t requiredSize = alignUp(size, 16)
+ signature.paramsSize()
+ signature.numParameters() * sizeof(bool) * 2;
return AlignedMemory::allocate(requiredSize, PARAMETERS_MIN_ALIGNMENT);
}
//! Deallocate the memory reserved for this instance.
void operator delete(void * ptr) { AlignedMemory::deallocate(ptr); }
//! Deallocate the memory reserved for this instance,
// matching overloaded operator new.
void operator delete(void * ptr, const KernelSignature& signature)
{ AlignedMemory::deallocate(ptr); }
//! Returns raw kernel parameters without capture
address values() const { return values_; }
//! Return true if the captured parameter at the given \a index is bound to
// SVM pointer.
bool boundToSvmPointer(const Device& device,
const_address capturedAddress,
size_t index) const;
//! add the svmPtr execInfo into container
void addSvmPtr(void* const* execInfoArray, size_t count)
{
execSvmPtr_.clear();
for (size_t i = 0; i < count; i++) {
execSvmPtr_.push_back(execInfoArray[i]);
}
}
//! get the number of svmPtr in the execInfo container
size_t getNumberOfSvmPtr() const {return execSvmPtr_.size();}
//! get the number of svmPtr in the execInfo container
size_t getExecInfoOffset() const {return execInfoOffset_;}
//! set the status of kernel support fine-grained SVM system pointer sharing
void setSvmSystemPointersSupport(FGSStatus svmSystemSupport) { svmSystemPointersSupport_ = svmSystemSupport; }
//! return the status of kernel support fine-grained SVM system pointer sharing
FGSStatus getSvmSystemPointersSupport() const { return svmSystemPointersSupport_; }
};
/*! \brief Encapsulates a __kernel function and the argument values
* to be used when invoking this function.
*/
class Kernel : public RuntimeObject
{
private:
//! The program where this kernel is defined.
SharedReference<Program> program_;
const Symbol& symbol_; //!< The symbol for this kernel.
std::string name_; //!< The kernel's name.
KernelParameters* parameters_; //!< The parameters.
protected:
//! Destroy this kernel
~Kernel();
public:
/*! \brief Construct a kernel object from the __kernel function
* \a kernelName in the given \a program.
*/
Kernel(Program& program, const Symbol& symbol, const std::string& name);
//! Return the program containing this kernel.
Program& program() const { return program_(); }
//! Return this kernel's signature.
const KernelSignature& signature() const;
//! Return the kernel entry point for the given device.
const device::Kernel* getDeviceKernel(
const Device& device, //!< Device object
bool noAlias = true //!< Controls alias optimization
) const;
//! Return the parameters.
KernelParameters& parameters() const { return *parameters_; }
//! Return the kernel's name.
const std::string& name() const { return name_; }
virtual ObjectType objectType() const {return ObjectTypeKernel;}
};
/*! @}
* @}
*/
} // namespace amd
#endif /*KERNEL_HPP_*/
File diff suppressed because it is too large Load Diff
+662
View File
@@ -0,0 +1,662 @@
//
// Copyright 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef MEMORY_H_
#define MEMORY_H_
#include "top.hpp"
#include "utils/flags.hpp"
#include "thread/atomic.hpp"
#include "thread/monitor.hpp"
#include "platform/context.hpp"
#include "platform/object.hpp"
#include "platform/interop.hpp"
#include "device/device.hpp"
#include <utility>
#include <vector>
#include <list>
#include <map>
namespace device {
class Memory;
class VirtualDevice;
}
namespace amd {
// Forward declaration of the amd::Image and amd::Buffer classes.
class Image;
class Buffer;
class Pipe;
struct BufferRect : public amd::EmbeddedObject
{
//! Default constructor
BufferRect()
: rowPitch_(0)
, slicePitch_(0)
, start_(0)
, end_(0)
{ }
//! Creates BufferRect object
bool create(
const size_t* bufferOrigin, //!< Start locaiton in the buffer
const size_t* region, //!< Copy region
size_t bufferRowPitch, //!< Provided buffer's row pitch
size_t bufferSlicePitch //!< Provided buffer's slice pitch
);
//! Returns the plain offset for the (X, Y, Z) location
size_t offset(
size_t x, //!< Coordinate in X dimension
size_t y, //!< Coordinate in Y dimension
size_t z //!< Coordinate in Z dimension
) const
{
return start_ + x + y * rowPitch_ + z * slicePitch_;
}
size_t rowPitch_; //!< Calculated row pitch for the buffer rect
size_t slicePitch_; //!< Calculated slice pitch for the buffer rect
size_t start_; //!< Start offset for the copy region
size_t end_; //!< Relative end offset from start for the copy region
};
class HostMemoryReference
{
public:
//! Default constructor
HostMemoryReference(void* hostMem = NULL)
: alloced_(false)
, hostMem_(hostMem)
, size_(0)
{}
//! Default destructor
~HostMemoryReference()
{
assert(!alloced_ && "Host buffer not deallocated");
}
//! Creates host memory reference object
bool allocateMemory(size_t size, const Context& context);
// Frees system memory if it was allocated
void deallocateMemory(const Context& context);
//! Get the host memory pointer
void* hostMem() const { return hostMem_; }
//! Get the host memory size
size_t size() const { return size_; }
//! Set the host memory pointer
void setHostMem(void* hostMem, const Context& context)
{
deallocateMemory(context);
hostMem_ = hostMem;
}
//! Returns true if the host memory has been allocated by this object, false
// if it has been allocated elsewhere.
bool alloced() const { return alloced_; }
private:
//! Disable copy constructor
HostMemoryReference(const HostMemoryReference&);
//! Disable operator=
HostMemoryReference& operator=(const HostMemoryReference&);
bool alloced_; //!< TRUE if memory was allocated
void* hostMem_; //!< Host memory pointer
size_t size_; //!< The host memory size
};
class Memory: public amd::RuntimeObject
{
typedef void (CL_CALLBACK * DestructorCallBackFunction)(
cl_mem memobj, void *user_data);
enum AllocState {
AllocInit = 0,
AllocCreate = 1,
AllocComplete = 2,
AllocRealloced = 3
};
struct DestructorCallBackEntry
{
struct DestructorCallBackEntry* next_;
DestructorCallBackFunction callback_;
void* data_;
DestructorCallBackEntry(
DestructorCallBackFunction callback, void* data) :
callback_(callback), data_(data)
{ }
};
protected:
typedef cl_mem_object_type Type;
typedef cl_mem_flags Flags;
typedef DeviceMap<const Device*, device::Memory*> DeviceMemory;
size_t numDevices_; //!< Number of devices
//! The device memory objects included in this memory
DeviceMemory* deviceMemories_;
//! The device alloced state
std::map<const Device*, AllocState> deviceAlloced_;
//! Linked list of destructor callbacks.
Atomic<DestructorCallBackEntry*> destructorCallbacks_;
SharedReference<Context> context_; //!< Owning context
Memory* parent_;
const Type type_; //!< Object type (Buffer, Image2D, Image3D)
HostMemoryReference hostMemRef_; //!< Host-side memory reference(or NULL if none)
size_t origin_;
size_t size_; //!< Size in bytes
Flags flags_; //!< Construction flags
size_t version_; //!< Update count, used for coherency
const Device* lastWriter_; //!< Which device wrote most recently (NULL if host)
InteropObject* interopObj_; //!< Interop object
bool isParent_; //!< This object is a parent
device::VirtualDevice* vDev_; //!< Memory object belongs to a virtual device only
bool forceSysMemAlloc_; //!< Forces system memory allocation
Atomic<uint> mapCount_; //!< Keep track of number of mappings for a memory object
void * svmHostAddress_; //!< svm host address;
bool svmPtrCommited_; //!< svm host address committed flag;
bool canBeCached_; //!< flag to if the object can be cached;
private:
//! Disable default assignment operator
Memory& operator=(const Memory&);
//! Disable default copy operator
Memory(const Memory&);
Monitor lockMemoryOps_; //!< Lock to serialize memory operations
std::list<Memory*> subBuffers_; //!< List of all subbuffers for this memory object
protected:
//! The constructor creates a memory object but does not allocate either host memory
//! or device memory. Default parameters are appropriate for Buffer creation.
Memory(
Context& context, //!< Context object
Type type, //!< Memory type
Flags flags, //!< Object's flags
size_t size, //!< Memory size
void* svmPtr = NULL //!< svm host memory address, NULL if no SVM mem object
);
Memory(
Memory& parent, //!< Context object
Flags flags, //!< Object's flags
size_t offset, //!< Memory offset
size_t size, //!< Memory size
Type type = 0 //!< Memory type
);
//! Memory object destructor
virtual ~Memory();
//! Copies initialization data to the backing store
virtual void copyToBackingStore(
void* initFrom //!< Pointer to the initialization memory
);
//! Initializes the device memory array
virtual void initDeviceMemory();
void setSize(size_t size) { size_ = size; }
void setInteropObj(InteropObject* obj) { interopObj_ = obj; }
public:
//! Placement new operator.
void* operator new(
size_t size, //!< Original allocation size
const Context& context //!< Context this memory object is allocated in.
);
// Provide a "matching" placement delete operator.
void operator delete(
void*, //!< Pointer to deallocate
const Context& context //!< Context this memory object is allocated in.
);
// and a regular delete operator to satisfy synthesized methods.
void operator delete(
void* //!< Pointer to deallocate
);
//! Returns the memory lock object
amd::Monitor& lockMemoryOps() { return lockMemoryOps_; }
//! Adds a view into the list
void addSubBuffer(Memory* item);
//! virtual function used to distinguish memory objects from other CL objects
virtual ObjectType objectType() const {return ObjectTypeMemory;}
//! Removes a subbuffer from the list
void removeSubBuffer(Memory* item);
//! Returns the list of all subbuffers
std::list<Memory*>& subBuffers() { return subBuffers_; }
//! Returns the number of devices
size_t numDevices() const { return numDevices_; }
//! static_cast to Buffer with sanity check
virtual Buffer* asBuffer() { return NULL; }
//! static_cast to Image with sanity check
virtual Image* asImage() { return NULL; }
//! static_cast to Pipe with sanity check
virtual Pipe* asPipe() { return NULL; }
//! Creates and initializes device (cache) memory for all devices
virtual bool create(
void* initFrom = NULL, //!< Pointer to the initialization data
bool sysMemAlloc = false //!< Allocate device memory in system memory
);
//! Allocates device (cache) memory for a specific device
bool addDeviceMemory(
const Device* dev //!< Device object
);
//! Replaces device (cache) memory for a specific device
void replaceDeviceMemory(
const Device* dev, //!< Device object
device::Memory* dm //!< New device memory object for replacement
);
//! Find the section for the given device. Return NULL if not found.
device::Memory* getDeviceMemory(
const Device& dev, //!< Device object
bool alloc = true //!< Allocates memory
);
//! Allocate host memory (as required)
bool allocHostMemory(
void* initFrom, //!< Host memory provided by the application
bool allocHostMem, //!< Force system memory allocation
bool forceCopy = false //!< Force system memory allocation
);
//! Checks if memory was reallocated
bool reallocedDeviceMemory(const Device* dev)
{ return (AllocRealloced == deviceAlloced_[dev]) ? true : false; }
// Accessors
Memory* parent() const { return parent_; }
bool isParent() const { return isParent_; }
size_t getOrigin() const { return origin_; }
size_t getSize() const { return size_; }
Flags getMemFlags() const { return flags_; }
Type getType() const { return type_; }
const Device* getLastWriter() { return lastWriter_; }
const HostMemoryReference* getHostMemRef() const { return &hostMemRef_; }
void* getHostMem() const { return hostMemRef_.hostMem(); }
void setHostMem(void* mem) { hostMemRef_.setHostMem(mem, context_()); }
size_t getVersion() const { return version_; }
Context& getContext() const { return context_(); }
bool isInterop() const { return (getInteropObj() != NULL) ? true : false ; }
InteropObject* getInteropObj() const { return interopObj_; }
bool setDestructorCallback(DestructorCallBackFunction callback, void* data);
//! Signal that a write has occurred to a cached version
void signalWrite(const Device* writer);
//! Force an asynchronous writeback from the most-recent dirty cache to host
void cacheWriteBack(void);
//! For CPU device only!
//! Base functions for mapping/unmapping GL/D3D objects
//! Functions may be left empty, if not needed
//! Virtual member function mapExtObjectInCQThread() maps a GL object
//! and store CPU memory pointer in Memory::hostMem_.
//! Returns true if ok, false 0 if error(s)
virtual bool mapExtObjectInCQThread(void) { return true;}
//! Virtual member functions unmapExtObjectInCQThread() unmaps a GL object
//! and clears pointer Memory::hostMem_.
//! Returns true if ok, false 0 if error(s)
virtual bool unmapExtObjectInCQThread(void) { return true; }
//! Returns true if the specified area covers memory intirely
virtual bool isEntirelyCovered(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const = 0;
//! Returns true if the specified area is not degenerate and is inside of allocated memory
virtual bool validateRegion(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const = 0;
void setVirtualDevice(device::VirtualDevice* vDev) { vDev_ = vDev; }
device::VirtualDevice* getVirtualDevice() const { return vDev_; }
bool forceSysMemAlloc() const { return forceSysMemAlloc_; }
void incMapCount() { ++mapCount_; }
void decMapCount() { --mapCount_; }
uint mapCount() const { return mapCount_; }
bool usesSvmPointer() const;
void * getSvmPtr() const { return svmHostAddress_; } //!< svm pointer accessor;
void setSvmPtr(void * ptr) { svmHostAddress_ = ptr; } //!< svm pointer setter;
bool isSvmPtrCommited() const { return svmPtrCommited_; } //!< svm host address committed accessor;
void commitSvmMemory(); //!< svm host address committed accessor;
void setCacheStatus(bool canBeCached) { canBeCached_ = canBeCached; }//!< set the memobject cached status;
bool canBeCached() const { return canBeCached_; } //!< get the memobject cached status;
};
//! Buffers are a specialization of memory. Just a wrapper, really,
//! but this gives us flexibility for later changes.
class Buffer: public Memory
{
protected:
cl_bus_address_amd busAddress_;
//! Initializes the device memory array which is nested
// after'Image1DD3D10' object in memory layout.
virtual void initDeviceMemory();
Buffer(Context& context, Type type, Flags flags, size_t size) :
Memory(context, type, flags, size)
{ }
public:
Buffer(Context& context, Flags flags, size_t size, void* svmPtr = NULL) :
Memory(context, CL_MEM_OBJECT_BUFFER, flags, size, svmPtr)
{ }
Buffer(Memory& parent, Flags flags, size_t origin, size_t size) :
Memory(parent, flags, origin, size)
{ }
bool create(
void* initFrom = NULL, //!< Pointer to the initialization data
bool sysMemAlloc = false //!< Allocate device memory in system memory
);
//! static_cast to Buffer with sanity check
virtual Buffer* asBuffer() { return this; }
//! Returns true if the specified area covers buffer entirely
bool isEntirelyCovered(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const;
//! Returns true if the specified area is not degenerate and is inside of allocated memory
bool validateRegion(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const;
cl_bus_address_amd busAddress() const { return busAddress_; }
};
//! Pipes are a specialization of Buffers.
class Pipe: public Buffer
{
protected:
size_t packetSize_; //!< Size in bytes of pipe packet
size_t maxPackets_; //!< Number of max pipe packets
bool initialized_; //!< Mark if the pipe is initialized
virtual void initDeviceMemory();
public:
Pipe(Context& context, Flags flags, size_t size, size_t pipe_packet_size, size_t pipe_max_packets)
: Buffer(context, CL_MEM_OBJECT_PIPE, flags, size)
, initialized_(false)
{
packetSize_ = pipe_packet_size;
maxPackets_ = pipe_max_packets;
}
//! static_cast to Pipe with sanity check
virtual Pipe* asPipe() { return this; }
//! Returns pipe size pitch in bytes
size_t getPacketSize() const { return packetSize_; }
//! return max number of pipe packets
size_t getMaxNumPackets() const { return maxPackets_; }
};
//! Images are a specialization of memory
class Image : public Memory
{
public:
// declaration of list of supported formats
static cl_image_format supportedFormats[];
static cl_image_format supportedFormatsRA[];
static cl_uint numSupportedFormats(const Context& context, cl_mem_object_type image_type, cl_mem_flags flags = 0);
static cl_uint getSupportedFormats(
const Context& context,
cl_mem_object_type image_type,
const cl_uint num_entries,
cl_image_format *image_formats,
cl_mem_flags flags = 0);
//! Helper struct to manipulate image formats.
struct Format : public cl_image_format
{
//! Construct a new ImageFormat wrapper.
Format(const cl_image_format& format) {
image_channel_order = format.image_channel_order;
image_channel_data_type = format.image_channel_data_type;
}
//! Return true if this is a valid image format, false otherwise.
bool isValid() const;
//! Returns true if this format is supported by runtime, false otherwise
bool isSupported(const Context& context, cl_mem_object_type image_type=0) const;
//! Compare 2 image formats.
bool operator == (const Format& rhs) const {
return image_channel_order == rhs.image_channel_order
&& image_channel_data_type == rhs.image_channel_data_type;
}
bool operator != (const Format& rhs) const { return !(*this == rhs); }
//! Return the number of channels.
size_t getNumChannels() const;
//! Return the element size in bytes.
size_t getElementSize() const;
//! Get the channel order by indices. R = 0, G = 1, B = 2, A = 3.
void getChannelOrder(uint8_t* channelOrder) const;
//! Adjust colorRGBA according to format, and set it in colorFormat.
void formatColor(const void* colorRGBA, void* colorFormat) const;
};
struct Impl
{
const amd::Coord3D region_;
size_t rp_;
size_t sp_;
const Format format_;
void* reserved_;
size_t bp_;
Impl(const Format& format, Coord3D region, size_t rp, size_t sp = 0, size_t bp = 0)
: region_(region), rp_(rp), sp_(sp), format_(format), bp_(bp)
{ DEBUG_ONLY(reserved_ = NULL); }
};
private:
Impl impl_; //!< Image object description
size_t dim_; //!< Image dimension
protected:
Image(
const Format& format,
Image& parent);
///! Initializes the device memory array which is nested
// after'Image' object in memory layout.
virtual void initDeviceMemory();
//! Copies initialization data to the backing store
virtual void copyToBackingStore(
void* initFrom //!< Pointer to the initialization memory
);
void initDimension();
public:
Image(
Context& context,
Type type,
Flags flags,
const Format& format,
size_t width,
size_t height,
size_t depth,
size_t rowPitch,
size_t slicePitch);
Image(
Buffer& buffer,
Type type,
Flags flags,
const Format& format,
size_t width,
size_t height,
size_t depth,
size_t rowPitch,
size_t slicePitch);
//! Validate image dimensions with supported sizes
static bool validateDimensions(
const std::vector<amd::Device*>& devices, //!< List of devices for validation
cl_mem_object_type type, //!< Image type
size_t width, //!< Image width
size_t height, //!< Image height
size_t depth, //!< Image depth
size_t arraySize //!< Image array size
);
const Format& getImageFormat() const {return impl_.format_;}
//! static_cast to Buffer with sanity check
virtual Image* asImage() { return this; }
//! Returns true if specified area covers image entirely
bool isEntirelyCovered(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const;
//! Returns true if the specified area is not degenerate and is inside of allocated memory
bool validateRegion(
const Coord3D& origin, //!< Origin location of the covered region
const Coord3D& region //!< Covered region dimensions
) const;
//! Returns true if the slice value for the image is valid
bool isSliceValid(
const size_t& rowPitch, //!< The row pitch value
const size_t& slicePitch, //!< The slice pitch value
const size_t& height //!< The height of the copy region
) const;
//! Creates a view memory object
virtual Image* createView(
const Context& context, //!< Context for a view creation
const Format& format, //!< The new format for a view
device::VirtualDevice* vDev //!< Virtual device object
);
//! Returns the impl for this image.
Impl& getImpl() { return impl_; }
//! Returns the number of dimensions.
size_t getDims() const { return dim_; }
//! Base virtual methods to be overridden in derived image classes
//!
//! Returns width of image in pixels
size_t getWidth() const { return impl_.region_[0]; }
//! Returns height of image in pixels
size_t getHeight() const { return impl_.region_[1]; }
//! Returns image's row pitch in bytes
size_t getRowPitch() const { return impl_.rp_; }
//! Returns image's byte pitch
size_t getBytePitch() const { return impl_.bp_; }
//! Returns depth of the image in pixels/slices
size_t getDepth() const { return impl_.region_[2]; }
//! Returns image's slice pitch in bytes
size_t getSlicePitch() const { return impl_.sp_; }
//! Get the image covered region
const Coord3D& getRegion() const { return impl_.region_; }
//! Sets the byte pitch obtained from HWL.
void setBytePitch(size_t bytePitch) { impl_.bp_ = bytePitch; }
//! Creates and initializes device (cache) memory for all devices
bool create(
void* initFrom = NULL //!< Pointer to the initialization data
);
};
//! SVM-related functionality.
class SvmBuffer : AllStatic
{
public:
//! Allocate a shared buffer that is accessible by all devices in the context
static void* malloc(
Context& context,
cl_svm_mem_flags flags,
size_t size,
size_t alignment);
//! Release shared buffer
static void free(Context& context, void* ptr);
//! Fill the destination buffer \a dst with the contents of the source
//! buffer \a src \times times.
static void memFill(
void* dst,
const void* src,
size_t srcSize,
size_t times);
//! Return true if \a ptr is a pointer allocated using SvmBuffer::malloc
//! that has not been deallocated afterwards
static bool malloced(const void* ptr);
private:
static void Add(uintptr_t k, uintptr_t v);
static void Remove(uintptr_t k);
static bool Contains(uintptr_t ptr);
static std::map<uintptr_t, uintptr_t> Allocated_; // !< Allocated buffers
static Monitor AllocatedLock_;
};
} // namespace amd
#endif // MEMORY_H_
+70
View File
@@ -0,0 +1,70 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/ndrange.hpp"
namespace amd {
NDRange::NDRange(size_t dimensions)
: dimensions_(dimensions)
{
*this = 0;
}
NDRange::NDRange(const NDRange& space)
: dimensions_(space.dimensions_)
{
*this = space;
}
NDRange&
NDRange::operator = (size_t x)
{
for (size_t i = 0; i < dimensions_; ++i) {
data_[i] = x;
}
return *this;
}
NDRange::~NDRange()
{
}
bool
NDRange::operator == (const NDRange& x) const
{
assert(dimensions_ == x.dimensions_ && "dimensions mismatch");
for (size_t i = 0; i < dimensions_; ++i) {
if (data_[i] != x.data_[i]) {
return false;
}
}
return true;
}
bool
NDRange::operator == (size_t x) const
{
for (size_t i = 0; i < dimensions_; ++i) {
if (data_[i] != x) {
return false;
}
}
return true;
}
#ifdef DEBUG
void
NDRange::printOn(FILE* file) const
{
fprintf(file, "[");
for (size_t i = dimensions_ - 1; i > 0; --i) {
fprintf(file, SIZE_T_FMT ", ", data_[i]);
}
fprintf(file, SIZE_T_FMT "]", data_[0]);
}
#endif // DEBUG
} // namespace amd
+213
View File
@@ -0,0 +1,213 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef NDRANGE_HPP_
#define NDRANGE_HPP_
#include "top.hpp"
#include <valarray>
#ifdef DEBUG
# include <cstdio>
#endif // DEBUG
namespace amd {
/*! \addtogroup Runtime
* @{
*
* \addtogroup Program Programs and Kernel functions
* @{
*/
//! An N-dimensions index space.
class NDRange : public EmbeddedObject
{
private:
const size_t dimensions_ : 2; //!< Number of dimensions [0-3]
size_t data_[3]; //!< indexes array
private:
//! Construct a new index space for an array of elements (no-copy)
NDRange(size_t dimensions, size_t* elements)
: dimensions_(dimensions)
{
for (uint i = 0; i < dimensions_; ++i) {
data_[i] = elements[i];
}
}
public:
//! Construct a new index space of the given dimensions.
explicit NDRange(size_t dimensions);
//! Copy constructor.
NDRange(const NDRange& space);
//! Destroy the index space.
~NDRange();
//! Copy operator
inline NDRange& operator = (const NDRange& space);
//! Make all elements of this space equal to x.
NDRange& operator = (size_t x);
//! Return the number of dimensions.
size_t dimensions() const { return dimensions_; }
//! Return the element at the given \a index.
size_t& operator [] (size_t index)
{
assert(index < dimensions_ && "index is out of bounds");
return data_[index];
}
//! Return the element at the given \a index.
size_t operator [] (size_t index) const
{
assert(index < dimensions_ && "index is out of bounds");
return data_[index];
}
//! Return the sum of this index space elements.
inline size_t sum() const;
//! Return the product of this index space elements (size)
inline size_t product() const;
// Binary operators:
inline friend NDRange operator + (const NDRange& x, const NDRange& y);
inline friend NDRange operator - (const NDRange& x, const NDRange& y);
inline friend NDRange operator * (const NDRange& x, const NDRange& y);
inline friend NDRange operator / (const NDRange& x, const NDRange& y);
inline friend NDRange operator % (const NDRange& x, const NDRange& y);
//! Return true if this index space is identical to \a x.
bool operator == (const NDRange& x) const;
//! Return true if this index space and \a x are different.
bool operator != (const NDRange& x) const { return !(*this == x); }
//! Return true if all elements are equal to \a x.
bool operator == (size_t x) const;
//! Return true if one element of this space is not equal to \a x.
bool operator != (size_t x) const { return !(*this == x); }
#ifdef DEBUG
//! Print this index space on the given stream.
void printOn(FILE* file) const;
#endif // DEBUG
};
//! A container for the local and global worksizes.
class NDRangeContainer : public HeapObject
{
private:
const size_t dimensions_; //!< Number of dimensions.
NDRange offset_; //!< Global work-item offset.
NDRange global_; //!< Total number of work-items in N-dims
NDRange local_; //!< Number of work-items in N-dims in a workgroup.
public:
/*! \brief Construct a new nd-range container with the given local
* and global worksizes in \a nDimensions dimensions.
*/
NDRangeContainer(
size_t dimensions,
const size_t* globalWorkOffset,
const size_t* globalWorkSize,
const size_t* localWorkSize
) : dimensions_(dimensions),
offset_(dimensions), global_(dimensions), local_(dimensions)
{
for (size_t i = 0; i < dimensions; ++i) {
offset_[i] = globalWorkOffset != NULL ? globalWorkOffset[i] : 0;
global_[i] = globalWorkSize[i];
local_[i] = localWorkSize[i];
}
}
//! Return the number of dimensions.
size_t dimensions() const { return dimensions_; }
//! Return the global workoffset.
const NDRange& offset() const { return offset_; }
NDRange& offset() { return offset_; }
//! Return the global worksize.
const NDRange& global() const { return global_; }
NDRange& global() { return global_; }
//! Return the local worksize.
const NDRange& local() const { return local_; }
NDRange& local() { return local_; }
};
/*! @}\
* @}
*/
inline size_t
NDRange::sum() const
{
size_t result = data_[0];
for (size_t i = 1; i < dimensions_; ++i) {
result += data_[i];
}
return result;
}
inline size_t
NDRange::product() const
{
size_t result = data_[0];
for (size_t i = 1; i < dimensions_; ++i) {
result *= data_[i];
}
return result;
}
// This function is in this header file for performance improvements:
inline NDRange&
NDRange::operator = (const NDRange& space)
{
assert(dimensions_ == space.dimensions_ && "dimensions mismatch");
for (size_t i = 0; i < sizeof(data_)/sizeof(*data_); ++i) {
data_[i] = space.data_[i];
}
return *this;
}
#define DEFINE_NDRANGE_BINARY_OP(op) \
inline NDRange \
operator op (const NDRange& x, const NDRange& y) \
{ \
assert(x.dimensions_ == y.dimensions_ && "dimensions mismatch"); \
\
size_t dimensions = x.dimensions_; \
size_t result[3] = {0}; \
for (size_t i = 0; i < dimensions; ++i) { \
result[i] = x.data_[i] op y.data_[i]; \
} \
\
return NDRange(dimensions, &result[0]); \
}
DEFINE_NDRANGE_BINARY_OP(+);
DEFINE_NDRANGE_BINARY_OP(-);
DEFINE_NDRANGE_BINARY_OP(*);
DEFINE_NDRANGE_BINARY_OP(/);
DEFINE_NDRANGE_BINARY_OP(%);
#undef DEFINE_NDRANGE_BINARY_OP
} // namespace amd
#endif /*NDRANGE_HPP_*/
+88
View File
@@ -0,0 +1,88 @@
//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/object.hpp"
#include <cstring>
namespace amd {
Atomic<ObjectMetadata::Key>
ObjectMetadata::nextKey_ = 1;
ObjectMetadata::Destructor
ObjectMetadata::destructors_[OCL_MAX_KEYS] = { NULL };
bool
ObjectMetadata::check(Key key)
{
return key > 0 && key <= OCL_MAX_KEYS;
}
ObjectMetadata::Key
ObjectMetadata::createKey(Destructor destructor)
{
Key key = nextKey_++;
if (!check(key)) {
return 0;
}
destructors_[key-1] = destructor;
return key;
}
ObjectMetadata::~ObjectMetadata()
{
if (!values_) {
return;
}
for (size_t i = 0; i < OCL_MAX_KEYS; ++i) {
if (values_[i] && destructors_[i]) {
destructors_[i](values_[i]);
}
}
delete[] values_;
}
void*
ObjectMetadata::getValueForKey(Key key) const
{
if (!values_ || !check(key)) {
return NULL;
}
return values_[key-1];
}
bool
ObjectMetadata::setValueForKey(Key key, Value value)
{
if (!check(key)) {
return false;
}
while (!values_) {
Value* values = new Value[OCL_MAX_KEYS];
memset(values, '\0', sizeof(Value) * OCL_MAX_KEYS);
if (!values_.compareAndSet(NULL, values)) {
delete[] values;
}
}
size_t index = key-1;
Value prev = AtomicOperation::swap(value, &values_[index]);
if (prev && destructors_[index] != NULL) {
destructors_[index](prev);
}
return true;
}
} // namespace amd
+270
View File
@@ -0,0 +1,270 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef OBJECT_HPP_
#define OBJECT_HPP_
#include "top.hpp"
#include "os/alloc.hpp"
#include "thread/monitor.hpp"
#include "utils/util.hpp"
#define CL_TYPES_DO(F) \
/* OpenCL type Runtime type */ \
F(cl_context, Context) \
F(cl_event, Event) \
F(cl_command_queue, CommandQueue) \
F(cl_kernel, Kernel) \
F(cl_program, Program) \
F(cl_device_id, Device) \
F(cl_mem, Memory) \
F(cl_sampler, Sampler) \
F(cl_counter_amd, Counter) \
F(cl_perfcounter_amd, PerfCounter) \
F(cl_video_session_amd, VideoSession) \
F(cl_threadtrace_amd, ThreadTrace)
// Forward declare ::cl_* types and amd::Class types
//
#define DECLARE_CL_TYPES(CL,AMD) \
namespace amd { class AMD; } \
typedef struct _##CL { } * CL;
CL_TYPES_DO(DECLARE_CL_TYPES);
#undef DECLARE_CL_TYPES
struct KHRicdVendorDispatchRec;
namespace amd {
// Define the cl_*_type tokens for type checking.
//
#define DEFINE_CL_TOKENS(CL,ignored) T##CL,
enum cl_token
{
Tinvalid = 0,
CL_TYPES_DO(DEFINE_CL_TOKENS)
numTokens
};
#undef DEFINE_CL_TOKENS
const size_t RuntimeObjectAlignment =
NextPowerOfTwo<numTokens>::value;
//! \cond ignore
template <typename T>
struct as_internal
{ typedef void type; };
template <typename T>
struct as_external
{ typedef void type; };
template <typename T>
struct class_token
{ static const cl_token value = Tinvalid; };
#define DEFINE_CL_TRAITS(CL,AMD) \
\
template <> \
struct class_token<AMD> \
{ static const cl_token value = T##CL; }; \
\
template <> \
struct as_internal<_##CL> \
{ typedef AMD type; }; \
template <> \
struct as_internal<const _##CL> \
{ typedef AMD const type; }; \
\
template <> \
struct as_external<AMD> \
{ typedef _##CL type; }; \
template <> \
struct as_external<const AMD> \
{ typedef _##CL const type; };
CL_TYPES_DO(DEFINE_CL_TRAITS);
#undef DEFINE_CL_TRAITS
//! \endcond
struct ICDDispatchedObject
{
static struct KHRicdVendorDispatchRec icdVendorDispatch_[];
const struct KHRicdVendorDispatchRec* const dispatch_;
protected:
ICDDispatchedObject() : dispatch_(icdVendorDispatch_) { }
public:
static bool isValidHandle(const void* handle)
{
return handle != NULL;
}
const void* handle() const
{
return static_cast<const ICDDispatchedObject*>(this);
}
void* handle()
{
return static_cast<ICDDispatchedObject*>(this);
}
template<typename T>
static const T* fromHandle(const void *handle)
{
return static_cast<const T*>(
reinterpret_cast<const ICDDispatchedObject*>(handle));
}
template<typename T>
static T* fromHandle(void *handle)
{
return static_cast<T*>(
reinterpret_cast<ICDDispatchedObject*>(handle));
}
};
#define OCL_MAX_KEYS 8
/*! The object metadata container.
*/
class ObjectMetadata
{
public:
typedef size_t Key;
typedef void* Value;
private:
typedef void (CL_CALLBACK * Destructor)(Value);
static Atomic<Key> nextKey_;
static Destructor destructors_[OCL_MAX_KEYS];
Atomic<Value*> values_;
public:
static bool check(Key key);
static Key createKey(Destructor destructor = NULL);
ObjectMetadata() : values_(NULL) { }
~ObjectMetadata();
Value getValueForKey(Key key) const;
bool setValueForKey(Key key, Value value);
};
/*! \brief For all OpenCL/Runtime objects.
*/
class RuntimeObject : public ReferenceCountedObject, public ICDDispatchedObject
{
private:
ObjectMetadata metadata_;
public:
enum ObjectType {
ObjectTypeContext = 0,
ObjectTypeDevice = 1,
ObjectTypeMemory = 2,
ObjectTypeKernel = 3,
ObjectTypeCounter = 4,
ObjectTypePerfCounter = 5,
ObjectTypeEvent = 6,
ObjectTypeProgram = 7,
ObjectTypeQueue = 8,
ObjectTypeSampler = 9,
ObjectTypeThreadTrace = 10,
ObjectTypeVideoSession= 11
};
ObjectMetadata& metadata() { return metadata_; }
virtual ObjectType objectType() const =0 ;
};
template <typename T>
class SharedReference : public EmbeddedObject
{
private:
T& reference_;
private:
// do not copy shared references.
SharedReference<T>& operator = (const SharedReference<T>& sref);
public:
explicit SharedReference(T& reference)
: reference_(reference)
{
reference_.retain();
}
~SharedReference()
{
reference_.release();
}
T& operator ()() const { return reference_; }
};
/*! \brief A 1,2 or 3D coordinate.
*!
*! Note, dimensionality is only defined for sizes, and is given by the number
*! of non-zero elements. (i.e. a 1D line is not the same as a 2D plane with width 1)
*/
struct Coord3D
{
size_t c[3];
Coord3D(size_t d0, size_t d1 = 0, size_t d2 = 0)
{
c[0]=d0; c[1]=d1; c[2]=d2;
}
const size_t& operator[] (size_t idx) const
{
assert(idx < 3);
return c[idx];
}
bool operator== (const Coord3D& rhs) const
{
return c[0] == rhs.c[0] && c[1] == rhs.c[1] && c[2] == rhs.c[2];
}
};
} // namespace amd
template <typename CL>
typename amd::as_internal<CL>::type*
as_amd(CL* cl_obj)
{
return cl_obj == NULL ? NULL : amd::RuntimeObject::fromHandle<
typename amd::as_internal<CL>::type>(static_cast<void*>(cl_obj));
}
template <typename AMD>
typename amd::as_external<AMD>::type*
as_cl(AMD* amd_obj)
{
return amd_obj == NULL ? NULL : static_cast<
typename amd::as_external<AMD>::type*>(amd_obj->handle());
}
template <typename CL>
bool
is_valid(CL* handle)
{
return amd::as_internal<CL>::type::isValidHandle(handle);
}
#endif /*OBJECT_HPP_*/
+65
View File
@@ -0,0 +1,65 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef PERFCTR_HPP_
#define PERFCTR_HPP_
#include "top.hpp"
#include "device/device.hpp"
#include "amdocl/cl_profile_amd.h"
namespace amd {
/*! \addtogroup Runtime
* @{
*
* \addtogroup Perfcounter
* @{
*/
/*! \class PerfCounter
*
* \brief The container class for the performance counters
*/
class PerfCounter : public RuntimeObject
{
public:
typedef std::map<cl_perfcounter_property, ulong> Properties;
//! Constructor of the performance counter object
PerfCounter(
const Device& device, //!< device object
Properties& properties) //!< a list of properties
: properties_(properties)
, deviceCounter_(NULL)
, device_(device)
{ }
//! Get the performance counter's result
const Device& device() const { return device_; }
//! Get the properties
const Properties& properties() const { return properties_; }
//! Get the device performance counter
const device::PerfCounter* getDeviceCounter() const { return deviceCounter_; }
//! Set the device performance counter
void setDeviceCounter(device::PerfCounter* counter) { deviceCounter_ = counter; }
//! RTTI internal implementation
virtual ObjectType objectType() const {return ObjectTypePerfCounter;}
protected:
//! Destructor for PerfCounter class
~PerfCounter() { delete deviceCounter_; }
Properties properties_; //!< the perf counter properties
device::PerfCounter* deviceCounter_; //!< device performance counter
const Device& device_; //!< the device object
};
/*@}*/
/*@}*/ } // namespace amd
#endif // PERFCTR_HPP_
+656
View File
@@ -0,0 +1,656 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/program.hpp"
#include "platform/context.hpp"
#include "utils/options.hpp"
#include <cstdlib> // for malloc
#include <cstring> // for strcmp
#include <utility>
namespace amd {
Program::~Program()
{
// Destroy all device programs
deviceprograms_t::const_iterator it, itEnd;
for (it = devicePrograms_.begin(), itEnd = devicePrograms_.end();
it != itEnd; ++it) {
delete it->second;
}
for (it = devProgramsNoOpt_.begin(), itEnd = devProgramsNoOpt_.end();
it != itEnd; ++it) {
delete it->second;
}
for (devicebinary_t::const_iterator IT = binary_.begin(), IE = binary_.end();
IT != IE; ++IT) {
const binary_t& Bin = IT->second;
if (Bin.first) {
delete [] Bin.first;
}
}
delete symbolTable_;
//! @todo Make sure we have destroyed all CPU specific objects
}
const Symbol*
Program::findSymbol(const char* kernelName) const
{
symbols_t::const_iterator it = symbolTable_->find(kernelName);
return (it == symbolTable_->end()) ? NULL : &it->second;
}
cl_int
Program::addDeviceProgram(Device& device, const void* image, size_t length, int oclVer)
{
if (image != NULL && !device.verifyBinaryImage(image, length)) {
return CL_INVALID_BINARY;
}
// Check if the device is already associated with this program
if (deviceList_.find(&device) != deviceList_.end()) {
return CL_INVALID_VALUE;
}
Device& rootDev = device.rootDevice();
// if the rootDev is already associated with a program
if (devicePrograms_[&rootDev] != NULL) {
return CL_SUCCESS;
}
device::Program* program = rootDev.createProgram(oclVer);
if (program == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
if (image != NULL) {
uint8_t* memory = binary(rootDev).first;
// clone 'binary' (it is owned by the host thread).
if (memory == NULL) {
memory = new (std::nothrow) uint8_t[length];
if (memory == NULL) {
delete program;
return CL_OUT_OF_HOST_MEMORY;
}
::memcpy(memory, image, length);
// Save the original image
binary_[&rootDev] = std::make_pair(memory, length);
}
if (!program->setBinary(reinterpret_cast<char *>(memory), length)) {
delete program;
return CL_INVALID_BINARY;
}
}
devicePrograms_[&rootDev] = program;
program = rootDev.createProgram(oclVer);
if (program == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
devProgramsNoOpt_[&rootDev] = program;
deviceList_.insert(&device);
return CL_SUCCESS;
}
device::Program*
Program::getDeviceProgram(const Device& device) const
{
deviceprograms_t::const_iterator it =
devicePrograms_.find(&device.rootDevice());
if (it == devicePrograms_.end()) {
return NULL;
}
return it->second;
}
Monitor
Program::buildLock_("OCL build program", true);
inline static int
GetOclCVersion(const char* clVer)
{
std::string clStd(clVer);
if (clStd == "CL1.0") {
return 100;
}
else if (clStd == "CL1.1") {
return 110;
}
else if (clStd == "CL1.2") {
return 120;
}
else {
if (clStd != "CL2.0") {
LogError("Unsupported OCL C version!");
}
return 200;
}
}
cl_int
Program::compile(
const std::vector<Device*>& devices,
size_t numHeaders,
const std::vector<const Program*>& headerPrograms,
const char** headerIncludeNames,
const char* options,
void (CL_CALLBACK * notifyFptr)(cl_program, void *),
void* data,
bool optionChangable)
{
ScopedLock sl(buildLock_);
cl_int retval = CL_SUCCESS;
// Clear the program object
clear();
// Process build options.
option::Options parsedOptions;
std::string cppstr(options ? options : "");
// if there is a -ignore-env, adjust options.
if (cppstr.size() > 0) {
// Set the options to be the string after -ignore-env
size_t pos = cppstr.find("-ignore-env");
if (pos != std::string::npos) {
cppstr = cppstr.substr(pos+sizeof("-ignore-env"));
optionChangable = false;
}
}
if (optionChangable) {
if (AMD_OCL_BUILD_OPTIONS != NULL) {
// Override options.
cppstr = AMD_OCL_BUILD_OPTIONS;
}
if (AMD_OCL_BUILD_OPTIONS_APPEND != NULL) {
cppstr.append(" ");
cppstr.append(AMD_OCL_BUILD_OPTIONS_APPEND);
}
}
if (!option::parseAllOptions(cppstr, parsedOptions)) {
programLog_ = parsedOptions.optionsLog();
return CL_INVALID_COMPILER_OPTIONS;
}
programLog_ = parsedOptions.optionsLog();
std::vector<const std::string*> headers(numHeaders);
for (size_t i = 0; i < numHeaders; ++i) {
const std::string& header = headerPrograms[i]->sourceCode();
headers[i] = &header;
}
// Compile the program programs associated with the given devices.
std::vector<Device*>::const_iterator it;
for (it = devices.begin(); it != devices.end(); ++it) {
device::Program* devProgram = getDeviceProgram(**it);
if (devProgram == NULL) {
const binary_t& bin = binary(**it);
const int oclVer = GetOclCVersion(parsedOptions.oVariables->CLStd);
retval = addDeviceProgram(**it, bin.first, bin.second, oclVer);
if (retval != CL_SUCCESS) {
return retval;
}
devProgram = getDeviceProgram(**it);
}
if (devProgram->type() == device::Program::TYPE_INTERMEDIATE) {
continue;
}
// We only build a Device-Program once
if (devProgram->buildStatus() != CL_BUILD_NONE) {
continue;
}
if (sourceCode_.empty()) {
return CL_INVALID_OPERATION;
}
cl_int result = devProgram->compile(
sourceCode_, headers,
headerIncludeNames,
options,
&parsedOptions);
// Check if the previous device failed a build
if ((result != CL_SUCCESS) && (retval != CL_SUCCESS)) {
retval = CL_INVALID_OPERATION;
}
// Update the returned value with a build error
else if (result != CL_SUCCESS) {
retval = result;
}
}
if (notifyFptr != NULL) {
notifyFptr(as_cl(this), data);
}
return retval;
}
cl_int
Program::link(
const std::vector<Device*>& devices,
size_t numInputs,
const std::vector<Program*>& inputPrograms,
const char* options,
void (CL_CALLBACK * notifyFptr)(cl_program, void *),
void* data,
bool optionChangable)
{
ScopedLock sl(buildLock_);
cl_int retval = CL_SUCCESS;
if (symbolTable_ == NULL) {
symbolTable_ = new symbols_t;
if (symbolTable_ == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
}
// Clear the program object
clear();
// Process build options.
option::Options parsedOptions;
std::string cppstr(options ? options : "");
// if there is a -ignore-env, adjust options.
if (cppstr.size() > 0) {
// Set the options to be the string after -ignore-env
size_t pos = cppstr.find("-ignore-env");
if (pos != std::string::npos) {
cppstr = cppstr.substr(pos+sizeof("-ignore-env"));
optionChangable = false;
}
}
if (optionChangable) {
if (AMD_OCL_LINK_OPTIONS != NULL) {
// Override options.
cppstr = AMD_OCL_LINK_OPTIONS;
}
if (AMD_OCL_LINK_OPTIONS_APPEND != NULL) {
cppstr.append(" ");
cppstr.append(AMD_OCL_LINK_OPTIONS_APPEND);
}
}
if (!option::parseLinkOptions(cppstr, parsedOptions)) {
programLog_ = parsedOptions.optionsLog();
return CL_INVALID_LINKER_OPTIONS;
}
programLog_ = parsedOptions.optionsLog();
// Link the program programs associated with the given devices.
std::vector<Device*>::const_iterator it;
for (it = devices.begin(); it != devices.end(); ++it) {
// find the corresponding device program in each input program
std::vector<device::Program*> inputDevPrograms(numInputs);
bool found = false;
int maxOclVer = GetOclCVersion(parsedOptions.oVariables->CLStd);
for (size_t i = 0; i < numInputs; ++i) {
Program& inputProgram = *inputPrograms[i];
deviceprograms_t inputDevProgs = inputProgram.devicePrograms();
deviceprograms_t::const_iterator findIt = inputDevProgs.find(*it);
if (findIt == inputDevProgs.end()) {
if (found) break;
continue;
}
found = true;
inputDevPrograms[i] = findIt->second;
size_t pos = inputDevPrograms[i]->compileOptions().find("-cl-std=");
if (pos != std::string::npos) {
std::string clStd =
inputDevPrograms[i]->compileOptions().substr((pos+8), 5);
int oclVer = GetOclCVersion(clStd.c_str());
maxOclVer = (maxOclVer > oclVer) ? maxOclVer : oclVer;
}
}
if (inputDevPrograms.size() == 0) {
continue;
}
if (inputDevPrograms.size() < numInputs) {
return CL_INVALID_VALUE;
}
device::Program* devProgram = getDeviceProgram(**it);
if (devProgram == NULL) {
const binary_t& bin = binary(**it);
retval = addDeviceProgram(**it, bin.first, bin.second, maxOclVer);
if (retval != CL_SUCCESS) {
return retval;
}
devProgram = getDeviceProgram(**it);
}
// We only build a Device-Program once
if (devProgram->buildStatus() != CL_BUILD_NONE) {
continue;
}
cl_int result = devProgram->link(
inputDevPrograms, options, &parsedOptions);
// Check if the previous device failed a build
if ((result != CL_SUCCESS) && (retval != CL_SUCCESS)) {
retval = CL_INVALID_OPERATION;
}
// Update the returned value with a build error
else if (result != CL_SUCCESS) {
retval = result;
}
}
// Rebuild the symbol table
deviceprograms_t::iterator sit;
for (sit = devicePrograms_.begin(); sit != devicePrograms_.end(); ++sit) {
const Device& device = *sit->first;
const device::Program& program = *sit->second;
const device::Program::kernels_t& kernels = program.kernels();
device::Program::kernels_t::const_iterator kit;
for (kit = kernels.begin(); kit != kernels.end(); ++kit) {
const std::string& name = kit->first;
const device::Kernel* devKernel = kit->second;
Symbol& symbol = (*symbolTable_)[name];
if (!symbol.setDeviceKernel(device, devKernel)) {
retval = CL_LINK_PROGRAM_FAILURE;
}
}
}
// Create a string with all kernel names from the program
if (kernelNames_.length() == 0) {
amd::Program::symbols_t::const_iterator it;
for (it = symbols().begin(); it != symbols().end(); ++it) {
if (it != symbols().begin()) {
kernelNames_.append(1, ';');
}
kernelNames_.append(it->first.c_str());
}
}
if (notifyFptr != NULL) {
notifyFptr(as_cl(this), data);
}
return retval;
}
cl_int
Program::build(
const std::vector<Device*>& devices,
const char* options,
void (CL_CALLBACK * notifyFptr)(cl_program, void *),
void* data,
bool optionChangable)
{
ScopedLock sl(buildLock_);
cl_int retval = CL_SUCCESS;
if (symbolTable_ == NULL) {
symbolTable_ = new symbols_t;
if (symbolTable_ == NULL) {
return CL_OUT_OF_HOST_MEMORY;
}
}
// Clear the program object
clear();
// Process build options.
option::Options parsedOptions;
std::string cppstr(options ? options : "");
// if there is a -ignore-env, adjust options.
if (cppstr.size() > 0) {
// Set the options to be the string after -ignore-env
size_t pos = cppstr.find("-ignore-env");
if (pos != std::string::npos) {
cppstr = cppstr.substr(pos+sizeof("-ignore-env"));
optionChangable = false;
}
}
if (optionChangable) {
if (AMD_OCL_BUILD_OPTIONS != NULL) {
// Override options.
cppstr = AMD_OCL_BUILD_OPTIONS;
}
if (AMD_OCL_BUILD_OPTIONS_APPEND != NULL) {
cppstr.append(" ");
cppstr.append(AMD_OCL_BUILD_OPTIONS_APPEND);
}
}
if (!option::parseAllOptions(cppstr, parsedOptions)) {
programLog_ = parsedOptions.optionsLog();
return CL_INVALID_BUILD_OPTIONS;
}
programLog_ = parsedOptions.optionsLog();
// Build the program programs associated with the given devices.
std::vector<Device*>::const_iterator it;
for (it = devices.begin(); it != devices.end(); ++it) {
device::Program* devProgram = getDeviceProgram(**it);
if (devProgram == NULL) {
const binary_t& bin = binary(**it);
const int oclVer = GetOclCVersion(parsedOptions.oVariables->CLStd);
if (sourceCode_.empty() && (bin.first == NULL)) {
retval = false;
continue;
}
retval = addDeviceProgram(**it, bin.first, bin.second, oclVer);
if (retval != CL_SUCCESS) {
return retval;
}
devProgram = getDeviceProgram(**it);
}
parsedOptions.oVariables->AssumeAlias = (*it)->settings().assumeAliases_;
// We only build a Device-Program once
if (devProgram->buildStatus() != CL_BUILD_NONE) {
continue;
}
cl_int result = devProgram->build(sourceCode_, options, &parsedOptions);
// Check if the previous device failed a build
if ((result != CL_SUCCESS) && (retval != CL_SUCCESS)) {
retval = CL_INVALID_OPERATION;
}
// Update the returned value with a build error
else if (result != CL_SUCCESS) {
retval = result;
}
}
// Rebuild the symbol table
deviceprograms_t::iterator sit;
for (sit = devicePrograms_.begin(); sit != devicePrograms_.end(); ++sit) {
const Device& device = *sit->first;
const device::Program& program = *sit->second;
const device::Program::kernels_t& kernels = program.kernels();
device::Program::kernels_t::const_iterator kit;
for (kit = kernels.begin(); kit != kernels.end(); ++kit) {
const std::string& name = kit->first;
const device::Kernel* devKernel = kit->second;
Symbol& symbol = (*symbolTable_)[name];
if (!symbol.setDeviceKernel(device, devKernel)) {
retval = CL_BUILD_PROGRAM_FAILURE;
}
}
}
// Create a string with all kernel names from the program
if (kernelNames_.length() == 0) {
amd::Program::symbols_t::const_iterator it;
for (it = symbols().begin(); it != symbols().end(); ++it) {
if (it != symbols().begin()) {
kernelNames_.append(1, ';');
}
kernelNames_.append(it->first.c_str());
}
}
if (notifyFptr != NULL) {
notifyFptr(as_cl(this), data);
}
return retval;
}
bool
Program::buildNoOpt(const Device& device, const std::string& kernelName)
{
ScopedLock sl(buildLock_);
// Don't allow multiple builds of program without optimizations
if (!firstBuildNoOpt_) {
return false;
}
firstBuildNoOpt_ = false;
symbols_t::const_iterator it = symbolTable_->find(kernelName);
assert((it != symbolTable_->end()) && "Kernel must be valid at this time");
const Symbol& progSymbol = it->second;
// Check if program already has unoptimized kernel
device::Kernel* devKernel = const_cast<device::Kernel*>
(progSymbol.getDeviceKernel(device, false));
if (devKernel != NULL) {
return true;
}
// Find the original program for build options string
deviceprograms_t::const_iterator pit = devicePrograms_.find(&device);
assert((pit != devicePrograms_.end()) && "Program must be valid at this time");
device::Program* orgProgram = pit->second;
// Process build options.
option::Options parsedOptions;
std::string cppstr(orgProgram->compileOptions());
if (AMD_OCL_BUILD_OPTIONS != NULL) {
// Override options.
cppstr = AMD_OCL_BUILD_OPTIONS;
}
if (AMD_OCL_BUILD_OPTIONS_APPEND != NULL) {
cppstr.append(" ");
cppstr.append(AMD_OCL_BUILD_OPTIONS_APPEND);
}
if (!option::parseAllOptions(cppstr, parsedOptions)) {
return false;
}
parsedOptions.optionsLog();
parsedOptions.oVariables->AssumeAlias = true;
parsedOptions.oVariables->ForceLLVM = true;
// Find the program without optimizaiton
pit = devProgramsNoOpt_.find(&device);
// Update the symbol table
if (pit != devProgramsNoOpt_.end()) {
device::Program& program = *pit->second;
const device::Program::binary_t& progBinary = orgProgram->binary();
if (!program.setBinary(reinterpret_cast<char *>(const_cast<void*>
(progBinary.first)), progBinary.second)) {
return false;
}
// Force recompilation from the binary only
if (CL_SUCCESS != program.build("", orgProgram->compileOptions().c_str(),
&parsedOptions)) {
return false;
}
const device::Program::kernels_t& kernels = program.kernels();
device::Program::kernels_t::const_iterator kit;
for (kit = kernels.begin(); kit != kernels.end(); ++kit) {
const std::string& name = kit->first;
const device::Kernel* devKernel = kit->second;
symbols_t::iterator sit = symbolTable_->find(name);
Symbol& symbol = sit->second;
if (!symbol.setDeviceKernel(device, devKernel, false)) {
return false;
}
}
}
return true;
}
void
Program::clear()
{
deviceprograms_t::iterator sit;
// Destroy old programs if we have any
for (sit = devicePrograms_.begin(); sit != devicePrograms_.end(); ++sit) {
// Destroy device program
delete sit->second;
}
for (sit = devProgramsNoOpt_.begin(); sit != devProgramsNoOpt_.end(); ++sit) {
// Destroy device program
delete sit->second;
}
devicePrograms_.clear();
devProgramsNoOpt_.clear();
deviceList_.clear();
if (symbolTable_) symbolTable_->clear();
kernelNames_.clear();
}
bool
Symbol::setDeviceKernel(
const Device& device,
const device::Kernel* func,
bool noAlias)
{
// FIXME_lmoriche: check that the signatures are compatible
if (deviceKernels_.size() == 0 || device.type() == CL_DEVICE_TYPE_CPU) {
signature_ = func->signature();
}
if (noAlias) {
deviceKernels_[&device] = func;
}
else {
devKernelsNoOpt_[&device] = func;
}
return true;
}
const device::Kernel*
Symbol::getDeviceKernel(const Device& device, bool noAlias) const
{
const devicekernels_t* devKernels =
(noAlias) ? &deviceKernels_ : &devKernelsNoOpt_;
devicekernels_t::const_iterator itEnd = devKernels->end();
devicekernels_t::const_iterator it = devKernels->find(&device);
if (it != itEnd) {
return it->second;
}
for (it = devKernels->begin(); it != itEnd; ++it) {
if (it->first->isAncestor(&device)) {
return it->second;
}
}
return NULL;
}
} // namespace amd
+200
View File
@@ -0,0 +1,200 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
/*! \file program.hpp
* \brief Declarations for Program and ProgramBinary objects.
*
* \author Laurent Morichetti (laurent.morichetti@amd.com)
* \date October 2008
*/
#ifndef PROGRAM_HPP_
#define PROGRAM_HPP_
#include "top.hpp"
#include "device/device.hpp"
#include "platform/object.hpp"
#include "platform/kernel.hpp"
#include <set>
#include <string>
#include <vector>
#include <map>
#include <utility>
namespace amd {
/*! \addtogroup Runtime
* @{
*
* \addtogroup Program Programs and Kernel functions
* @{
*/
//! A kernel function symbol
class Symbol : public HeapObject
{
public:
typedef std::map<const Device*, const device::Kernel*> devicekernels_t;
private:
devicekernels_t deviceKernels_; //! All device kernels objects.
devicekernels_t devKernelsNoOpt_; //! Kernel objects without optimization
KernelSignature signature_; //! Kernel signature.
public:
//! Default constructor
Symbol() {}
//! Set the entry point and check or set the signature.
bool setDeviceKernel(
const Device& device, //!< Device object.
const device::Kernel* func, //!< Device kernel object.
bool noAlias = true //!< No-alias optimization
);
//! Return the device kernel.
const device::Kernel* getDeviceKernel(
const Device& device, //!< Device object.
bool noAlias = true //!< No-alias optimization
) const;
//! Return this Symbol's signature.
const KernelSignature& signature() const { return signature_; }
};
class Context;
//! A collection of binaries for devices in the associated context.
class Program : public RuntimeObject
{
public:
typedef std::pair<uint8_t*, size_t> binary_t;
typedef std::set<Device const*> devicelist_t;
typedef std::map<Device const*, binary_t> devicebinary_t;
typedef std::map<Device const*, device::Program*> deviceprograms_t;
typedef std::map<std::string, Symbol> symbols_t;
private:
//! The context this program is part of.
SharedReference<Context> context_;
std::string sourceCode_; //!< Strings that make up the source code
devicebinary_t binary_; //!< The binary image, provided by the app
symbols_t* symbolTable_; //!< The program's kernels symbol table
std::string kernelNames_; //!< The program kernel names
//! The device program objects included in this program
deviceprograms_t devicePrograms_;
deviceprograms_t devProgramsNoOpt_;
devicelist_t deviceList_;
std::string programLog_; //!< Log for parsing options, etc.
bool firstBuildNoOpt_; //!< Build program without optimizations
protected:
//! Destroy this program.
~Program();
//! Clears the program object if the app attempts to rebuild the program
void clear();
//! Global build lock (remove when LLVM is thread-safe).
static Monitor buildLock_;
public:
//! Construct a new program to be compiled from the given source code.
Program(Context& context, const std::string& sourceCode)
: context_(context)
, sourceCode_(sourceCode)
, symbolTable_(NULL)
, programLog_()
, firstBuildNoOpt_(true)
{ }
//! Construct a new program associated with a context.
Program(Context& context)
: context_(context)
, symbolTable_(NULL)
{ }
//! Returns context, associated with the current program.
const Context& context() const { return context_(); }
//! Return the sections for this program.
const deviceprograms_t& devicePrograms() const { return devicePrograms_; }
//! Return the associated devices.
const devicelist_t& deviceList() const { return deviceList_; }
//! Return the symbols for this program.
const symbols_t& symbols() const { return *symbolTable_; }
//! Return the program source code.
const std::string& sourceCode() const { return sourceCode_; }
//! Return the program log.
const std::string& programLog() const { return programLog_; }
//! Add a binary image to this program.
cl_int addDeviceProgram(Device&, const void* image = NULL,
size_t len = 0, int oclVer = 120);
//! Find the section for the given device. Return NULL if not found.
device::Program* getDeviceProgram(const Device& device) const;
//! Return the symbol for the given kernel name.
const Symbol* findSymbol(const char* name) const;
//! Return the binary image.
const binary_t& binary(const Device& device) {
return binary_[&device.rootDevice()];
}
//! Return the program kernel names
const std::string& kernelNames() const { return kernelNames_; }
//! Compile the program for the given devices.
cl_int compile(
const std::vector<Device*>& devices,
size_t numHeaders,
const std::vector<const Program*>& headerPrograms,
const char** headerIncludeNames,
const char* options = NULL,
void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,
void* data = NULL,
bool optionChangable = true);
//! Link the programs for the given devices.
cl_int link(
const std::vector<Device*>& devices,
size_t numInputs,
const std::vector<Program*>& inputPrograms,
const char* options = NULL,
void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,
void* data = NULL,
bool optionChangable = true);
//! Build the program for the given devices.
cl_int build(
const std::vector<Device*>& devices,
const char* options = NULL,
void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,
void* data = NULL,
bool optionChangable = true);
//! Build the program for the given devices without noalias optimization
bool buildNoOpt(const Device& device, const std::string& kernelName);
//! RTTI internal implementation
virtual ObjectType objectType() const {return ObjectTypeProgram;}
};
/*! @}
* @}
*/
} // namespace amd
#endif /*PROGRAM_HPP_*/
+183
View File
@@ -0,0 +1,183 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#include "platform/runtime.hpp"
#include "thread/atomic.hpp"
#include "os/os.hpp"
#include "thread/thread.hpp"
#include "device/device.hpp"
#include "utils/flags.hpp"
#include "utils/options.hpp"
#include "platform/context.hpp"
#include "platform/agent.hpp"
#include "amdocl/cl_gl_amd.hpp"
#ifdef _WIN32
#include <d3d10_1.h>
#include <dxgi.h>
#include "CL/cl_d3d10.h"
#endif //_WIN32
#if defined(_MSC_VER) //both Win32 and Win64
#include <intrin.h>
#endif
#include <cstdlib>
#include <iostream>
#ifdef TIMEBOMB
# include <cstdio>
# include <time.h>
#endif // TIMEBOMB
namespace amd {
#ifdef __linux__
static void __runtime_exit() __attribute__((destructor(102)));
static void __runtime_exit()
{
if (ENABLE_CAL_SHUTDOWN) {
Runtime::tearDown();
}
}
#endif
volatile bool
Runtime::initialized_ = false;
bool
Runtime::init()
{
if (initialized_) {
return true;
}
// Enter a very basic critical region. We want to prevent 2 threads
// from concurrently executing the init() routines. We can't use a
// Monitor since the system is not yet initialized.
static Atomic<int> lock = 0;
struct CriticalRegion
{
Atomic<int>& lock_;
CriticalRegion(Atomic<int>& lock) : lock_(lock)
{
while (true) {
if (lock == 0 && lock.swap(1) == 0) {
break;
}
Os::yield();
}
}
~CriticalRegion()
{
lock_.storeRelease(0);
}
} region(lock);
if (initialized_) {
return true;
}
#ifdef TIMEBOMB
time_t current = time(NULL);
time_t expiration = TIMEBOMB;
if (current > expiration) {
fprintf(stderr, "Expired on %s", asctime(gmtime(&expiration)));
return false;
}
else {
fprintf(stderr, "For test only: Expires on %s",
asctime(gmtime(&expiration)));
}
#endif // TIMEBOMB
if ( !Flag::init()
|| !option::init()
|| !Device::init()
// Agent initializes last
|| !Agent::init()) {
return false;
}
initialized_ = true;
return true;
}
void
Runtime::tearDown()
{
if (!initialized_) {
return;
}
Agent::tearDown();
Device::tearDown();
option::teardown();
Flag::tearDown();
}
uint
ReferenceCountedObject::retain()
{
return ++make_atomic(referenceCount_);
}
uint
ReferenceCountedObject::release()
{
uint newCount = --make_atomic(referenceCount_);
if (newCount == 0) {
if (terminate()) {
delete this;
}
}
return newCount;
}
#ifdef _WIN32
#ifdef DEBUG
static int
reportHook(int reportType, char *message, int *returnValue)
{
std::cerr << message;
::exit(3);
return TRUE;
}
#endif // DEBUG
extern "C" BOOL WINAPI
DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
# ifdef DEBUG
if (AMD_OCL_SUPPRESS_MESSAGE_BOX) {
_CrtSetReportHook(reportHook);
_set_error_mode(_OUT_TO_STDERR);
}
# endif // DEBUG
break;
case DLL_PROCESS_DETACH:
if (!reserved || ENABLE_CAL_SHUTDOWN) {
Runtime::tearDown();
}
break;
case DLL_THREAD_DETACH: {
amd::Thread* thread = amd::Thread::current();
delete thread;
}
break;
default:
break;
}
return true;
}
#endif
} // namespace amd
+76
View File
@@ -0,0 +1,76 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef RUNTIME_HPP_
#define RUNTIME_HPP_
#include "top.hpp"
#include "thread/thread.hpp"
namespace amd {
/*! \addtogroup Runtime The OpenCL Runtime
* @{
*/
class Runtime : AllStatic
{
static volatile bool initialized_;
public:
//! Return true if the OpencCL runtime is already initialized
inline static bool initialized();
//! Initialize the OpenCL runtime.
static bool init();
//! Tear down the runtime.
static void tearDown();
//! Return true if the Runtime is still single-threaded.
static bool singleThreaded() { return !initialized(); }
};
#if 0
class HostThread : public Thread
{
private:
virtual void run(void* data) { ShouldNotCallThis(); }
public:
HostThread() : Thread("HostThread", 0, false)
{
setHandle(NULL);
setCurrent();
if (!amd::Runtime::initialized() && !amd::Runtime::init()) {
return;
}
Os::currentStackInfo(&stackBase_, &stackSize_);
setState(RUNNABLE);
}
bool isHostThread() const { return true; };
static inline HostThread* current()
{
Thread* thread = Thread::current();
assert(thread->isHostThread() && "just checking");
return (HostThread*) thread;
}
};
#endif
/*@}*/
inline bool
Runtime::initialized()
{
return initialized_;
}
} // namespace amd
#endif /*RUNTIME_HPP_*/
+175
View File
@@ -0,0 +1,175 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef SAMPLER_HPP_
#define SAMPLER_HPP_
#include "top.hpp"
#include "platform/object.hpp"
#include "device/device.hpp"
namespace amd
{
//! Abstraction layer sampler class
class Sampler : public RuntimeObject
{
public:
typedef std::map<Device const*, device::Sampler*> DeviceSamplers;
//! \note the sampler states must match the compiler's defines.
//! See amd_ocl_sys_predef.c
enum State
{
StateNormalizedCoordsFalse = 0x00,
StateNormalizedCoordsTrue = 0x01,
StateNormalizedCoordsMask = (StateNormalizedCoordsFalse |
StateNormalizedCoordsTrue),
StateAddressNone = 0x00,
StateAddressRepeat = 0x02,
StateAddressClampToEdge = 0x04,
StateAddressClamp = 0x06,
StateAddressMirroredRepeat = 0x08,
StateAddressMask = (StateAddressNone |
StateAddressRepeat |
StateAddressMirroredRepeat |
StateAddressClampToEdge |
StateAddressClamp),
StateFilterNearest = 0x10,
StateFilterLinear = 0x20,
StateFilterMask = (StateFilterNearest |
StateFilterLinear)
};
private:
Context& context_; //!< OpenCL context associated with this sampler
uint32_t state_; //!< Sampler state
DeviceSamplers deviceSamplers_; //!< Container for the device samplers
public:
Sampler(
Context& context, //!< OpenCL context
bool norm_coords, //!< normalized coordinates
uint addr_mode, //!< adressing mode
uint filter_mode //!< filter mode
)
: context_(context)
{ // Packs the sampler state into uint32_t for kernel execution
state_ = 0;
// Set normalized state
if (norm_coords) {
state_ |= StateNormalizedCoordsTrue;
}
else {
state_ |= StateNormalizedCoordsFalse;
}
// Program the sampler filter mode
if (filter_mode == CL_FILTER_LINEAR) {
state_ |= StateFilterLinear;
}
else {
state_ |= StateFilterNearest;
}
// Program the sampler address mode
switch (addr_mode) {
case CL_ADDRESS_CLAMP_TO_EDGE:
state_ |= StateAddressClampToEdge;
break;
case CL_ADDRESS_REPEAT:
state_ |= StateAddressRepeat;
break;
case CL_ADDRESS_CLAMP:
state_ |= StateAddressClamp;
break;
case CL_ADDRESS_MIRRORED_REPEAT:
state_ |= StateAddressMirroredRepeat;
break;
case CL_ADDRESS_NONE:
state_ |= StateAddressNone;
break;
default:
break;
}
}
virtual ~Sampler()
{
for (DeviceSamplers::const_iterator it = deviceSamplers_.begin();
it != deviceSamplers_.end(); ++it) {
delete it->second;
}
}
bool create()
{
for (uint i = 0; i < context_.devices().size(); ++i) {
device::Sampler* sampler = NULL;
Device* dev = context_.devices()[i];
if (!dev->createSampler(*this, &sampler)) {
return false;
}
deviceSamplers_[dev] = sampler;
}
return true;
}
device::Sampler* getDeviceSampler(const Device& dev) const
{
DeviceSamplers::const_iterator it = deviceSamplers_.find(&dev);
if (it != deviceSamplers_.end()) {
return it->second;
}
return NULL;
}
//! Accessor functions
Context& context() const { return context_; }
uint32_t state() const { return state_; }
bool normalizedCoords() const
{
return (state_ & StateNormalizedCoordsTrue) ? true : false;
}
uint addressingMode() const
{
uint adressing = 0;
// Program the sampler address mode
switch (state_ & StateAddressMask) {
case StateAddressRepeat:
adressing = CL_ADDRESS_REPEAT;
break;
case StateAddressClampToEdge:
adressing = CL_ADDRESS_CLAMP_TO_EDGE;
break;
case StateAddressClamp:
adressing = CL_ADDRESS_CLAMP;
break;
case StateAddressMirroredRepeat:
adressing = CL_ADDRESS_MIRRORED_REPEAT;
break;
case StateAddressNone:
adressing = CL_ADDRESS_NONE;
break;
default:
break;
}
return adressing;
}
uint filterMode() const
{
return ((state_ & StateFilterMask) == StateFilterNearest) ?
CL_FILTER_NEAREST : CL_FILTER_LINEAR;
}
//! RTTI internal implementation
virtual ObjectType objectType() const { return ObjectTypeSampler; }
};
} // namespace amd
#endif /*SAMPLER_HPP_*/
+129
View File
@@ -0,0 +1,129 @@
//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef THREAD_TRACE_HPP_
#define THREAD_TRACE_HPP_
#include "top.hpp"
#include "device/device.hpp"
#include "amdocl/cl_thread_trace_amd.h"
namespace amd {
#define THREAD_TRACE_BUFFER_DEFAULT_SIZE 4096
/*! \addtogroup Runtime
* @{
*
* \addtogroup Threadtrace
* @{
*/
/*! \class ThreadTrace
*
* \brief The container class for the thread traces
*/
class ThreadTrace : public RuntimeObject
{
public:
enum State {
None,
MemoryBound,
Begin,
End,
Pause
};
typedef struct ThreadTraceConfigRec
{
size_t configSize_; // structure size
size_t cu_; // target compute unit [cu]
size_t sh_; // target shader array [sh],that contains target cu
size_t simdMask_; // bitmask to enable or disable target tokens for different SIMDs
size_t vmIdMask_; // virtual memory [vm] IDs to capture
size_t tokenMask_; // bitmask indicating which trace token IDs will be included in the trace
size_t regMask_; // bitmask indicating which register types should be included in the trace
size_t instMask_; // types of instruction scheduling updates which should be recorded
size_t randomSeed_; // linear feedback shift register [LFSR] seed
size_t userData_; // user data ,which is written as payload
size_t captureMode_; // indicator for the way how THREAD_TRACE_START / STOP events affect token collection
bool isUserData_; // indicator if user_data is set
bool isWrapped_; // indicator if the memory buffer should be wrapped around instead of stopping at the end
//default thread trace configuration/s initializator
ThreadTraceConfigRec():configSize_(0),cu_(0),sh_(0),simdMask_(0xF),vmIdMask_(CL_THREAD_TRACE_VM_ID_MASK_SINGLE),
tokenMask_(CL_THREAD_TRACE_TOKEN_MASK_ALL_SI),regMask_(CL_THREAD_TRACE_REG_MASK_ALL_SI),
instMask_(CL_THREAD_TRACE_INST_MASK_ALL),randomSeed_(0xFFF),userData_(0),
captureMode_(CL_THREAD_TRACE_CAPTURE_ALL),isUserData_(false),isWrapped_(false){
configSize_ = sizeof(struct ThreadTraceConfigRec);
}
}ThreadTraceConfig;
//! Constructor of the thread trace object
ThreadTrace(
const Device& device) //!< device object
: deviceThreadTrace_(NULL)
,device_(device)
,state_(None)
{ }
//! Get the thread trace's associated device
const Device& device() const { return device_; }
//! Get the shader engines number for thread trace`s associated device
const size_t deviceSeNumThreadTrace() const { return device_.info().numberOfShaderEngines; }
//! Get the device thread trace
device::ThreadTrace* getDeviceThreadTrace() { return deviceThreadTrace_; }
//! Set the device thread trace
void setDeviceThreadTrace(device::ThreadTrace* threadTrace) { deviceThreadTrace_ = threadTrace; }
void setState(State state) {state_ = state;}
State getState() {return state_;}
void setCU(unsigned int cu) { threadTraceConfig_.cu_ = cu; }
void setSH(unsigned int sh) { threadTraceConfig_.sh_ = sh; }
void setSIMD(unsigned int simdMask) { threadTraceConfig_.simdMask_ = simdMask; }
void setUserData(unsigned int userData) {
threadTraceConfig_.isUserData_ = true;
threadTraceConfig_.userData_ = userData;
}
void setTokenMask(unsigned int tokenMask) { threadTraceConfig_.tokenMask_ = tokenMask; }
void setRegMask(unsigned int regMask) { threadTraceConfig_.regMask_ = regMask; }
void setVmIdMask(unsigned int vmIdMask) { threadTraceConfig_.vmIdMask_ = vmIdMask; }
void setInstMask(unsigned int instMask) { threadTraceConfig_.instMask_ = instMask; }
void setRandomSeed(unsigned int randomSeed) { threadTraceConfig_.randomSeed_ = randomSeed; }
void setCaptureMode(unsigned int captureMode) { threadTraceConfig_.captureMode_ = captureMode; }
void setIsWrapped(bool isWrapped) { threadTraceConfig_.isWrapped_ = isWrapped; }
const ThreadTraceConfig& threadTraceConfig() const {return threadTraceConfig_;}
//! RTTI internal implementation
virtual ObjectType objectType() const {return ObjectTypeThreadTrace;}
protected:
//! Destructor for ThreadTrace class
~ThreadTrace() {
delete deviceThreadTrace_;
}
device::ThreadTrace* deviceThreadTrace_; //!< device thread trace object
const Device& device_; //!< the device object
State state_;
ThreadTraceConfig threadTraceConfig_;
};
/*@}*/
/*@}*/ } // namespace amd
#endif // THREAD_TRACE_HPP_
+79
View File
@@ -0,0 +1,79 @@
//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef VIDEO_SESSION_HPP_
#define VIDEO_SESSION_HPP_
#include "top.hpp"
#include "platform/object.hpp"
#include "device/device.hpp"
#include "platform/commandqueue.hpp"
#if cl_amd_open_video
namespace amd
{
//! VideoSession class
class VideoSession : public RuntimeObject
{
private:
Context& context_; //!< OpenCL context
Device& device_; //!< OpenCL device
HostQueue* queue_; //!< Open CL video command queue
cl_bitfield& video_session_flags_; //!< Creation flags
cl_video_config_type_amd type_; //!< config buffer type
cl_uint size_; //!< config buffer size
void* buffer_; //!< pointer to config buffer
public:
VideoSession(
Context& context, //!< OpenCL context
Device& device, //!< OpenCL device
HostQueue* queue, //!< OpenCL command queue
cl_bitfield flags, //!< Video Session flags
cl_video_config_type_amd type, //!< config buffer type
cl_uint size, //!< config buffer size
void* buffer //!< pointer to config buffer
)
: context_(context)
, device_(device)
, queue_(queue)
, video_session_flags_(flags)
, type_(type)
, size_(size)
, buffer_(NULL)
{
if (size > 0 && buffer) {
buffer_ = new char[size];
memcpy(buffer_, buffer, size);
}
}
virtual ~VideoSession()
{
if (queue_) {
queue_->release();
}
if (buffer_) {
delete[] static_cast<char*>(buffer_);
}
}
//! Accessor functions
Context& context() const { return context_; }
Device& device() const { return device_; }
HostQueue& queue() const { return *queue_; }
cl_bitfield& flags() const { return video_session_flags_; }
cl_video_config_type_amd type() const { return type_; }
void * configbuffer() const {return buffer_;}
//! RTTI internal implementation
virtual ObjectType objectType() const {return ObjectTypeVideoSession;}
};
} // namespace amd
#endif // cl_amd_open_video
#endif /*VIDEO_SESSION_HPP_*/