initial commit
This commit is contained in:
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
@@ -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 {
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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
|
||||
@@ -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_*/
|
||||
@@ -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_*/
|
||||
@@ -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_
|
||||
@@ -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_*/
|
||||
Reference in New Issue
Block a user