@@ -0,0 +1,149 @@
|
||||
//
|
||||
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "top.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "utils/flags.hpp"
|
||||
#include "appprofile.hpp"
|
||||
|
||||
static void* __stdcall adlMallocCallback(int n)
|
||||
{
|
||||
return malloc(n);
|
||||
}
|
||||
|
||||
#define GETPROCADDRESS(_adltype_, _adlfunc_) (_adltype_)amd::Os::getSymbol(adlHandle_, #_adlfunc_);
|
||||
|
||||
namespace amd {
|
||||
|
||||
ADL::ADL() : adlHandle_(NULL),
|
||||
adlContext_(NULL)
|
||||
{
|
||||
adl2MainControlCreate = NULL;
|
||||
adl2MainControlDestroy = NULL;
|
||||
adl2ConsoleModeFileDescriptorSet = NULL;
|
||||
adl2MainControlRefresh = NULL;
|
||||
adl2ApplicationProfilesSystemReload = NULL;
|
||||
adl2ApplicationProfilesProfileOfApplicationx2Search = NULL;
|
||||
}
|
||||
|
||||
ADL::~ADL()
|
||||
{
|
||||
if (adl2MainControlDestroy != NULL) {
|
||||
adl2MainControlDestroy(adlContext_);
|
||||
}
|
||||
adlContext_ = NULL;
|
||||
}
|
||||
|
||||
bool ADL::init()
|
||||
{
|
||||
if (!adlHandle_) {
|
||||
adlHandle_ = amd::Os::loadLibrary("atiadl" LP64_SWITCH(LINUX_SWITCH("xx", "xy"), "xx"));
|
||||
}
|
||||
|
||||
if (!adlHandle_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
adl2MainControlCreate = GETPROCADDRESS(Adl2MainControlCreate, ADL2_Main_Control_Create);
|
||||
adl2MainControlDestroy = GETPROCADDRESS(Adl2MainControlDestroy, ADL2_Main_Control_Destroy);
|
||||
adl2ConsoleModeFileDescriptorSet = GETPROCADDRESS(Adl2ConsoleModeFileDescriptorSet, ADL2_ConsoleMode_FileDescriptor_Set);
|
||||
adl2MainControlRefresh = GETPROCADDRESS(Adl2MainControlRefresh, ADL2_Main_Control_Refresh);
|
||||
adl2ApplicationProfilesSystemReload = GETPROCADDRESS(Adl2ApplicationProfilesSystemReload,
|
||||
ADL2_ApplicationProfiles_System_Reload);
|
||||
adl2ApplicationProfilesProfileOfApplicationx2Search = GETPROCADDRESS(Adl2ApplicationProfilesProfileOfApplicationx2Search,
|
||||
ADL2_ApplicationProfiles_ProfileOfAnApplicationX2_Search);
|
||||
|
||||
if (adl2MainControlCreate == NULL
|
||||
|| adl2MainControlDestroy == NULL
|
||||
|| adl2MainControlRefresh == NULL
|
||||
|| adl2ApplicationProfilesSystemReload == NULL
|
||||
|| adl2ApplicationProfilesProfileOfApplicationx2Search == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = adl2MainControlCreate(adlMallocCallback, 1, &adlContext_);
|
||||
if (result != ADL_OK) {
|
||||
// ADL2 is expected to return ADL_ERR_NO_XDISPLAY in Linux Console mode environment
|
||||
if (result == ADL_ERR_NO_XDISPLAY) {
|
||||
if(adl2ConsoleModeFileDescriptorSet == NULL
|
||||
|| adl2ConsoleModeFileDescriptorSet(adlContext_, ADL_UNSET) != ADL_OK) {
|
||||
return false;
|
||||
}
|
||||
adl2MainControlRefresh(adlContext_);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = adl2ApplicationProfilesSystemReload(adlContext_);
|
||||
if (result != ADL_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AppProfile::AppProfile(): hsaDeviceHint_(0),
|
||||
gpuvmHighAddr_(false),
|
||||
noHsaInit_(false),
|
||||
profileOverridesAllSettings_(false)
|
||||
{
|
||||
appFileName_ = amd::Os::getAppFileName();
|
||||
}
|
||||
|
||||
AppProfile::~AppProfile()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool AppProfile::init()
|
||||
{
|
||||
if (appFileName_.empty()){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert appName to wide char for X2_Search ADL interface
|
||||
size_t strLength = appFileName_.length() + 1;
|
||||
wchar_t *appName = new wchar_t[strLength];
|
||||
|
||||
size_t success = mbstowcs(appName, appFileName_.c_str(), strLength);
|
||||
if (success > 0) {
|
||||
// mbstowcs was able to convert to wide character successfully.
|
||||
appName[strLength - 1] = L'\0';
|
||||
}
|
||||
|
||||
wsAppFileName_ = appName;
|
||||
|
||||
delete appName;
|
||||
|
||||
ParseApplicationProfile();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cl_device_type AppProfile::ApplyHsaDeviceHintFlag(const cl_device_type& type)
|
||||
{
|
||||
cl_device_type ret_type = type;
|
||||
|
||||
bool isHsaHintSpecified = (type & (CL_HSA_ENABLED_AMD|CL_HSA_DISABLED_AMD))
|
||||
!= 0;
|
||||
// Apply app profile hsa device hint only if
|
||||
// HSA_RUNTIME is not set/defined *and*
|
||||
// no hsa hint flag already specified.
|
||||
// OR
|
||||
// Profile overridess all other settings (HSA_RUNTIME and hint flags).
|
||||
if ( profileOverridesAllSettings_
|
||||
|| (flagIsDefault(HSA_RUNTIME) && !isHsaHintSpecified)) {
|
||||
// Clear current hsa hint.
|
||||
ret_type = type & ~(CL_HSA_ENABLED_AMD | CL_HSA_DISABLED_AMD);
|
||||
// Apply hsa hint from app profile.
|
||||
return (ret_type | hsaDeviceHint_);
|
||||
}
|
||||
|
||||
// Do not apply app profile hsa device hint.
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef APPPROFILE_HPP_
|
||||
#define APPPROFILE_HPP_
|
||||
|
||||
#include "adl.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace amd {
|
||||
|
||||
class ADL {
|
||||
public:
|
||||
ADL();
|
||||
~ADL();
|
||||
|
||||
bool init();
|
||||
|
||||
void* adlHandle() const { return adlHandle_; };
|
||||
ADL_CONTEXT_HANDLE adlContext() const { return adlContext_; }
|
||||
|
||||
typedef int (*Adl2MainControlCreate)(ADL_MAIN_MALLOC_CALLBACK callback,
|
||||
int iEnumConnectedAdapters,
|
||||
ADL_CONTEXT_HANDLE* context);
|
||||
typedef int (*Adl2MainControlDestroy)(ADL_CONTEXT_HANDLE context);
|
||||
typedef int (*Adl2ConsoleModeFileDescriptorSet)(ADL_CONTEXT_HANDLE context, int fileDescriptor);
|
||||
typedef int (*Adl2MainControlRefresh)(ADL_CONTEXT_HANDLE context);
|
||||
typedef int (*Adl2ApplicationProfilesSystemReload)(ADL_CONTEXT_HANDLE context);
|
||||
typedef int (*Adl2ApplicationProfilesProfileOfApplicationx2Search)(ADL_CONTEXT_HANDLE context,
|
||||
const wchar_t* fileName,
|
||||
const wchar_t* path,
|
||||
const wchar_t* version,
|
||||
const wchar_t* appProfileArea,
|
||||
ADLApplicationProfile** lppProfile);
|
||||
|
||||
Adl2MainControlCreate adl2MainControlCreate;
|
||||
Adl2MainControlDestroy adl2MainControlDestroy;
|
||||
Adl2ConsoleModeFileDescriptorSet adl2ConsoleModeFileDescriptorSet;
|
||||
Adl2MainControlRefresh adl2MainControlRefresh;
|
||||
Adl2ApplicationProfilesSystemReload adl2ApplicationProfilesSystemReload;
|
||||
Adl2ApplicationProfilesProfileOfApplicationx2Search adl2ApplicationProfilesProfileOfApplicationx2Search;
|
||||
|
||||
private:
|
||||
void* adlHandle_;
|
||||
ADL_CONTEXT_HANDLE adlContext_;
|
||||
};
|
||||
|
||||
class AppProfile {
|
||||
public:
|
||||
AppProfile();
|
||||
virtual ~AppProfile();
|
||||
|
||||
bool init();
|
||||
|
||||
cl_device_type ApplyHsaDeviceHintFlag(const cl_device_type& type);
|
||||
bool IsHsaInitDisabled() { return noHsaInit_; }
|
||||
|
||||
protected:
|
||||
std::string appFileName_; // without extension
|
||||
std::wstring wsAppFileName_;
|
||||
|
||||
virtual bool ParseApplicationProfile() { return true; }
|
||||
|
||||
cl_device_type hsaDeviceHint_; // valid values: CL_HSA_ENABLED_AMD
|
||||
// or CL_HSA_DISABLED_AMD
|
||||
bool gpuvmHighAddr_; // Currently not used.
|
||||
bool noHsaInit_; // Do not even initialize HSA.
|
||||
bool profileOverridesAllSettings_; // Overrides hint flags and env.var.
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,737 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "platform/commandqueue.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/blit.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
|
||||
namespace device {
|
||||
|
||||
HostBlitManager::HostBlitManager(VirtualDevice& vDev, Setup setup)
|
||||
: BlitManager(setup)
|
||||
, vDev_(vDev)
|
||||
, dev_(vDev.device())
|
||||
{ }
|
||||
|
||||
bool
|
||||
HostBlitManager::readBuffer(
|
||||
device::Memory& srcMemory,
|
||||
void* dstHost,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
// Map the device memory to CPU visible
|
||||
void* src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly);
|
||||
if (NULL == src) {
|
||||
LogError("Couldn't map device memory for host read");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy memory
|
||||
amd::Os::fastMemcpy(dstHost,
|
||||
reinterpret_cast<const_address>(src) + origin[0], size[0]);
|
||||
|
||||
// Unmap device memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::readBufferRect(
|
||||
device::Memory& srcMemory,
|
||||
void* dstHost,
|
||||
const amd::BufferRect& bufRect,
|
||||
const amd::BufferRect& hostRect,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t srcOffset;
|
||||
size_t dstOffset;
|
||||
|
||||
for (size_t z = 0; z < size[2]; ++z) {
|
||||
for (size_t y = 0; y < size[1]; ++y) {
|
||||
srcOffset = bufRect.offset(0, y, z);
|
||||
dstOffset = hostRect.offset(0, y, z);
|
||||
|
||||
// Copy memory line by line
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dstHost) + dstOffset),
|
||||
(reinterpret_cast<const_address>(src) + srcOffset),
|
||||
size[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap source memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::readImage(
|
||||
device::Memory& srcMemory,
|
||||
void* dstHost,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
size_t rowPitch,
|
||||
size_t slicePitch,
|
||||
bool entire) const
|
||||
{
|
||||
size_t startLayer = origin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (srcMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = origin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t srcRowPitch;
|
||||
size_t srcSlicePitch;
|
||||
|
||||
// Get physical GPU memmory
|
||||
void* src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly,
|
||||
startLayer, numLayers, &srcRowPitch, &srcSlicePitch);
|
||||
if (NULL == src) {
|
||||
LogError("Couldn't map GPU memory for host read");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t elementSize = srcMemory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
size_t srcOffsBase = origin[0] * elementSize;
|
||||
size_t copySize = size[0] * elementSize;
|
||||
size_t srcOffs;
|
||||
size_t dstOffs = 0;
|
||||
|
||||
// Make sure we use the right pitch if it's not specified
|
||||
if (rowPitch == 0) {
|
||||
rowPitch = size[0] * elementSize;
|
||||
}
|
||||
|
||||
// Make sure we use the right slice if it's not specified
|
||||
if (slicePitch == 0) {
|
||||
slicePitch = size[0] * size[1] * elementSize;
|
||||
}
|
||||
|
||||
// Adjust destination offset with Y dimension
|
||||
srcOffsBase += srcRowPitch * origin[1];
|
||||
|
||||
// Adjust the destination offset with Z dimension
|
||||
srcOffsBase += srcSlicePitch * origin[2];
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
srcOffs = srcOffsBase + slice * srcSlicePitch;
|
||||
dstOffs = slice * slicePitch;
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t row = 0; row < size[1]; ++row) {
|
||||
// Copy memory
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dstHost) + dstOffs),
|
||||
(reinterpret_cast<const_address>(src) + srcOffs),
|
||||
copySize);
|
||||
|
||||
srcOffs += srcRowPitch;
|
||||
dstOffs += rowPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap the device memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::writeBuffer(
|
||||
const void* srcHost,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
uint flags = 0;
|
||||
if (entire) {
|
||||
flags = Memory::CpuWriteOnly;
|
||||
}
|
||||
|
||||
// Map the device memory to CPU visible
|
||||
void* dst = dstMemory.cpuMap(vDev_, flags);
|
||||
if (NULL == dst) {
|
||||
LogError("Couldn't map GPU memory for host write");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy memory
|
||||
amd::Os::fastMemcpy(
|
||||
reinterpret_cast<address>(dst) + origin[0], srcHost, size[0]);
|
||||
|
||||
// Unmap the device memory
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::writeBufferRect(
|
||||
const void* srcHost,
|
||||
device::Memory& dstMemory,
|
||||
const amd::BufferRect& hostRect,
|
||||
const amd::BufferRect& bufRect,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t srcOffset;
|
||||
size_t dstOffset;
|
||||
|
||||
for (size_t z = 0; z < size[2]; ++z) {
|
||||
for (size_t y = 0; y < size[1]; ++y) {
|
||||
srcOffset = hostRect.offset(0, y, z);
|
||||
dstOffset = bufRect.offset(0, y, z);
|
||||
|
||||
// Copy memory line by line
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffset),
|
||||
(reinterpret_cast<const_address>(srcHost) + srcOffset),
|
||||
size[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap destination memory
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::writeImage(
|
||||
const void* srcHost,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
size_t rowPitch,
|
||||
size_t slicePitch,
|
||||
bool entire) const
|
||||
{
|
||||
uint flags = 0;
|
||||
if (entire) {
|
||||
flags = Memory::CpuWriteOnly;
|
||||
}
|
||||
|
||||
size_t startLayer = origin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (dstMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = origin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t dstRowPitch;
|
||||
size_t dstSlicePitch;
|
||||
// Map the device memory to CPU visible
|
||||
void* dst = dstMemory.cpuMap(vDev_, flags,
|
||||
startLayer, numLayers, &dstRowPitch, &dstSlicePitch);
|
||||
if (NULL == dst) {
|
||||
LogError("Couldn't map GPU memory for host write");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t elementSize = dstMemory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
size_t srcOffs = 0;
|
||||
size_t copySize = size[0] * elementSize;
|
||||
size_t dstOffsBase = origin[0] * elementSize;
|
||||
size_t dstOffs;
|
||||
|
||||
// Make sure we use the right pitch if it's not specified
|
||||
if (rowPitch == 0) {
|
||||
rowPitch = size[0] * elementSize;
|
||||
}
|
||||
|
||||
// Make sure we use the right slice if it's not specified
|
||||
if (slicePitch == 0) {
|
||||
slicePitch = size[0] * size[1] * elementSize;
|
||||
}
|
||||
|
||||
// Adjust the destination offset with Y dimension
|
||||
dstOffsBase += dstRowPitch * origin[1];
|
||||
|
||||
// Adjust the destination offset with Z dimension
|
||||
dstOffsBase += dstSlicePitch * origin[2];
|
||||
|
||||
// Copy memory slice by slice
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
dstOffs = dstOffsBase + slice * dstSlicePitch;
|
||||
srcOffs = slice * slicePitch;
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t row = 0; row < size[1]; ++row) {
|
||||
// Copy memory
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffs),
|
||||
(reinterpret_cast<const_address>(srcHost) + srcOffs),
|
||||
copySize);
|
||||
|
||||
dstOffs += dstRowPitch;
|
||||
srcOffs += rowPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap the device memory
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::copyBuffer(
|
||||
device::Memory& srcMemory,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& srcOrigin,
|
||||
const amd::Coord3D& dstOrigin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_,
|
||||
// Overlap detection
|
||||
(&srcMemory == &dstMemory) ? 0 : Memory::CpuReadOnly);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Straight forward buffer copy
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOrigin[0]),
|
||||
(reinterpret_cast<const_address>(src) + srcOrigin[0]),
|
||||
size[0]);
|
||||
|
||||
// Unmap source and destination memory
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::copyBufferRect(
|
||||
device::Memory& srcMemory,
|
||||
device::Memory& dstMemory,
|
||||
const amd::BufferRect& srcRect,
|
||||
const amd::BufferRect& dstRect,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_,
|
||||
// Overlap detection
|
||||
(&srcMemory == &dstMemory) ? 0 : Memory::CpuReadOnly);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t z = 0; z < size[2]; ++z) {
|
||||
for (size_t y = 0; y < size[1]; ++y) {
|
||||
size_t srcOffset = srcRect.offset(0, y, z);
|
||||
size_t dstOffset = dstRect.offset(0, y, z);
|
||||
|
||||
// Copy memory line by line
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffset),
|
||||
(reinterpret_cast<const_address>(src) + srcOffset),
|
||||
size[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap source and destination memory
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::copyImageToBuffer(
|
||||
device::Memory& srcMemory,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& srcOrigin,
|
||||
const amd::Coord3D& dstOrigin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire,
|
||||
size_t rowPitch,
|
||||
size_t slicePitch) const
|
||||
{
|
||||
size_t startLayer = srcOrigin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (srcMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = srcOrigin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t srcRowPitch;
|
||||
size_t srcSlicePitch;
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly,
|
||||
startLayer, numLayers, &srcRowPitch, &srcSlicePitch);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
size_t elementSize = srcMemory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t srcOffs = srcOrigin[0];
|
||||
size_t dstOffs = dstOrigin[0];
|
||||
size_t srcOffsOrg;
|
||||
size_t copySize = size[0];
|
||||
|
||||
// Calculate the offset in bytes
|
||||
srcOffs *= elementSize;
|
||||
copySize *= elementSize;
|
||||
|
||||
// Adjust source offset with Y and Z dimensions
|
||||
srcOffs += srcRowPitch * srcOrigin[1];
|
||||
srcOffs += srcSlicePitch * srcOrigin[2];
|
||||
|
||||
srcOffsOrg = srcOffs;
|
||||
|
||||
// Copy memory slice by slice
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
srcOffs = srcOffsOrg + slice * srcSlicePitch;
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t rows = 0; rows < size[1]; ++rows) {
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffs),
|
||||
(reinterpret_cast<const_address>(src) + srcOffs),
|
||||
copySize);
|
||||
|
||||
srcOffs += srcRowPitch;
|
||||
dstOffs += copySize;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap source and destination memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::copyBufferToImage(
|
||||
device::Memory& srcMemory,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& srcOrigin,
|
||||
const amd::Coord3D& dstOrigin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire,
|
||||
size_t rowPitch,
|
||||
size_t slicePitch) const
|
||||
{
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t startLayer = dstOrigin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (dstMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = dstOrigin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t dstRowPitch;
|
||||
size_t dstSlicePitch;
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0,
|
||||
startLayer, numLayers, &dstRowPitch, &dstSlicePitch);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t elementSize = dstMemory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
size_t srcOffs = srcOrigin[0];
|
||||
size_t dstOffs = dstOrigin[0];
|
||||
size_t dstOffsOrg;
|
||||
size_t copySize = size[0];
|
||||
|
||||
// Calculate the offset in bytes
|
||||
dstOffs *= elementSize;
|
||||
copySize *= elementSize;
|
||||
|
||||
// Adjust destination offset with Y and Z dimension
|
||||
dstOffs += dstRowPitch * dstOrigin[1];
|
||||
dstOffs += dstSlicePitch * dstOrigin[2];
|
||||
|
||||
dstOffsOrg = dstOffs;
|
||||
|
||||
// Copy memory slice by slice
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
dstOffs = dstOffsOrg + slice * dstSlicePitch;
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t rows = 0; rows < size[1]; ++rows) {
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffs),
|
||||
(reinterpret_cast<const_address>(src) + srcOffs),
|
||||
copySize);
|
||||
|
||||
srcOffs += copySize;
|
||||
dstOffs += dstRowPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap source and destination memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::copyImage(
|
||||
device::Memory& srcMemory,
|
||||
device::Memory& dstMemory,
|
||||
const amd::Coord3D& srcOrigin,
|
||||
const amd::Coord3D& dstOrigin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire) const
|
||||
{
|
||||
size_t startLayer = srcOrigin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (srcMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = srcOrigin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t srcRowPitch;
|
||||
size_t srcSlicePitch;
|
||||
// Map source memory
|
||||
void *src = srcMemory.cpuMap(vDev_, Memory::CpuReadOnly,
|
||||
startLayer, numLayers, &srcRowPitch, &srcSlicePitch);
|
||||
if (src == NULL) {
|
||||
LogError("Couldn't map source memory");
|
||||
return false;
|
||||
}
|
||||
if (dstMemory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = dstOrigin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
else {
|
||||
startLayer = dstOrigin[2];
|
||||
numLayers = size[2];
|
||||
}
|
||||
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t dstRowPitch;
|
||||
size_t dstSlicePitch;
|
||||
// Map destination memory
|
||||
void *dst = dstMemory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0,
|
||||
startLayer, numLayers, &dstRowPitch, &dstSlicePitch);
|
||||
if (dst == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t elementSize = dstMemory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
assert(elementSize == srcMemory.owner()->asImage()->getImageFormat().getElementSize());
|
||||
|
||||
size_t srcOffs = srcOrigin[0];
|
||||
size_t dstOffs = dstOrigin[0];
|
||||
size_t srcOffsOrg;
|
||||
size_t dstOffsOrg;
|
||||
size_t copySize = size[0];
|
||||
|
||||
// Calculate the offsets in bytes
|
||||
srcOffs *= elementSize;
|
||||
dstOffs *= elementSize;
|
||||
copySize *= elementSize;
|
||||
|
||||
// Adjust destination and sorce offsets with Y dimension
|
||||
srcOffs += srcRowPitch * srcOrigin[1];
|
||||
dstOffs += dstRowPitch * dstOrigin[1];
|
||||
|
||||
// Adjust destination and sorce offsets with Z dimension
|
||||
srcOffs += srcSlicePitch * srcOrigin[2];
|
||||
dstOffs += dstSlicePitch * dstOrigin[2];
|
||||
|
||||
srcOffsOrg = srcOffs;
|
||||
dstOffsOrg = dstOffs;
|
||||
|
||||
// Copy memory slice by slice
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
srcOffs = srcOffsOrg + slice * srcSlicePitch;
|
||||
dstOffs = dstOffsOrg + slice * dstSlicePitch;
|
||||
|
||||
// Copy memory line by line
|
||||
for (size_t rows = 0; rows < size[1]; ++rows) {
|
||||
amd::Os::fastMemcpy(
|
||||
(reinterpret_cast<address>(dst) + dstOffs),
|
||||
(reinterpret_cast<const_address>(src) + srcOffs),
|
||||
copySize);
|
||||
|
||||
srcOffs += srcRowPitch;
|
||||
dstOffs += dstRowPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap source and destination memory
|
||||
srcMemory.cpuUnmap(vDev_);
|
||||
dstMemory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::fillBuffer(
|
||||
device::Memory& memory,
|
||||
const void* pattern,
|
||||
size_t patternSize,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire
|
||||
) const
|
||||
{
|
||||
// Map memory
|
||||
void* fillMem = memory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0);
|
||||
if (fillMem == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t offset = origin[0];
|
||||
size_t fillSize = size[0];
|
||||
|
||||
if ((fillSize % patternSize) != 0) {
|
||||
LogError("Misaligned buffer size and pattern size!");
|
||||
}
|
||||
|
||||
// Fill the buffer memory with a pattern
|
||||
for (size_t i = 0; i < (fillSize / patternSize); i++) {
|
||||
memcpy(
|
||||
(reinterpret_cast<address>(fillMem) + offset),
|
||||
(reinterpret_cast<const_address>(pattern)),
|
||||
patternSize
|
||||
);
|
||||
offset += patternSize;
|
||||
}
|
||||
|
||||
// Unmap source and destination memory
|
||||
memory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HostBlitManager::fillImage(
|
||||
device::Memory& memory,
|
||||
const void* pattern,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& size,
|
||||
bool entire
|
||||
) const
|
||||
{
|
||||
size_t startLayer = origin[2];
|
||||
size_t numLayers = size[2];
|
||||
if (memory.owner()->getType() == CL_MEM_OBJECT_IMAGE1D_ARRAY) {
|
||||
startLayer = origin[1];
|
||||
numLayers = size[1];
|
||||
}
|
||||
// rowPitch and slicePitch in bytes
|
||||
size_t devRowPitch;
|
||||
size_t devSlicePitch;
|
||||
// Map memory
|
||||
void* fillMem = memory.cpuMap(vDev_, (entire) ? Memory::CpuWriteOnly : 0,
|
||||
startLayer, numLayers, &devRowPitch, &devSlicePitch);
|
||||
if (fillMem == NULL) {
|
||||
LogError("Couldn't map destination memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
float fillValue[4];
|
||||
memset(fillValue, 0, sizeof(fillValue));
|
||||
memory.owner()->asImage()->getImageFormat().formatColor(pattern, fillValue);
|
||||
|
||||
size_t elementSize = memory.owner()->asImage()->getImageFormat().getElementSize();
|
||||
size_t offset = origin[0] * elementSize;
|
||||
size_t offsetOrg;
|
||||
|
||||
// Adjust offset with Y dimension
|
||||
offset += devRowPitch * origin[1];
|
||||
|
||||
// Adjust offset with Z dimension
|
||||
offset += devSlicePitch * origin[2];
|
||||
|
||||
offsetOrg = offset;
|
||||
|
||||
// Fill the image memory with a pattern
|
||||
for (size_t slice = 0; slice < size[2]; ++slice) {
|
||||
offset = offsetOrg + slice * devSlicePitch;
|
||||
|
||||
for (size_t rows = 0; rows < size[1]; ++rows) {
|
||||
size_t pixOffset = offset;
|
||||
|
||||
// Copy memory pixel by pixel
|
||||
for (size_t column = 0; column < size[0]; ++column) {
|
||||
memcpy(
|
||||
(reinterpret_cast<address>(fillMem) + pixOffset),
|
||||
(reinterpret_cast<const_address>(fillValue)),
|
||||
elementSize
|
||||
);
|
||||
pixOffset += elementSize;
|
||||
}
|
||||
|
||||
offset += devRowPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap memory
|
||||
memory.cpuUnmap(vDev_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,369 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef BLIT_HPP_
|
||||
#define BLIT_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "device/device.hpp"
|
||||
|
||||
/*! \addtogroup GPU Blit Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Blit Manager Implementation
|
||||
namespace device {
|
||||
|
||||
//! Blit Manager Abstraction class
|
||||
class BlitManager : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! HW accelerated setup
|
||||
union Setup {
|
||||
struct {
|
||||
uint disableReadBuffer_ : 1;
|
||||
uint disableReadBufferRect_ : 1;
|
||||
uint disableReadImage_ : 1;
|
||||
uint disableWriteBuffer_ : 1;
|
||||
uint disableWriteBufferRect_ : 1;
|
||||
uint disableWriteImage_ : 1;
|
||||
uint disableCopyBuffer_ : 1;
|
||||
uint disableCopyBufferRect_ : 1;
|
||||
uint disableCopyImageToBuffer_ : 1;
|
||||
uint disableCopyBufferToImage_ : 1;
|
||||
uint disableCopyImage_ : 1;
|
||||
uint disableFillBuffer_ : 1;
|
||||
uint disableFillImage_ : 1;
|
||||
uint disableCopyBufferToImageOpt_: 1;
|
||||
};
|
||||
uint32_t value_;
|
||||
Setup() : value_(0) {}
|
||||
void disableAll() { value_ = 0xffffffff; }
|
||||
};
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
BlitManager(
|
||||
Setup setup = Setup() //!< Specifies HW accelerated blits
|
||||
) : setup_(setup), syncOperation_(false) {}
|
||||
|
||||
//! Destructor
|
||||
virtual ~BlitManager() { }
|
||||
|
||||
//! Creates HostBlitManager object
|
||||
virtual bool create(amd::Device& device) { return true; }
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBuffer(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBufferRect(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destinaiton host memory
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies an image object to system memory
|
||||
virtual bool readImage(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBuffer(
|
||||
const void* srcHost, //!< Source host memory
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBufferRect(
|
||||
const void* srcHost, //!< Source host memory
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies system memory to an image object
|
||||
virtual bool writeImage(
|
||||
const void* srcHost, //!< Source host memory
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBuffer(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBufferRect(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& srcRect, //!< Source rectangle
|
||||
const amd::BufferRect& dstRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Copies an image object to a buffer object
|
||||
virtual bool copyImageToBuffer(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const = 0;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
virtual bool copyBufferToImage(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const = 0;
|
||||
|
||||
//! Copies an image object to another image object
|
||||
virtual bool copyImage(
|
||||
Memory& srcMemory, //!< Source memory object
|
||||
Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Fills a buffer memory with a pattern data
|
||||
virtual bool fillBuffer(
|
||||
Memory& memory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
size_t patternSize, //!< Pattern size
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Fills an image memory with a pattern data
|
||||
virtual bool fillImage(
|
||||
Memory& dstMemory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const = 0;
|
||||
|
||||
//! Enables synchronization on blit operations
|
||||
void enableSynchronization() { syncOperation_ = true; }
|
||||
|
||||
protected:
|
||||
const Setup setup_; //!< HW accelerated blit requested
|
||||
bool syncOperation_; //!< Blit operations are synchronized
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
BlitManager(const BlitManager&);
|
||||
|
||||
//! Disable operator=
|
||||
BlitManager& operator=(const BlitManager&);
|
||||
};
|
||||
|
||||
//! Host Blit Manager
|
||||
class HostBlitManager : public device::BlitManager
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
HostBlitManager(
|
||||
VirtualDevice& vdev, //!< Virtual GPU to be used for blits
|
||||
Setup setup = Setup() //!< Specifies HW accelerated blits
|
||||
);
|
||||
|
||||
//! Destructor
|
||||
virtual ~HostBlitManager() { }
|
||||
|
||||
//! Creates HostBlitManager object
|
||||
virtual bool create(amd::Device& device) { return true; }
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destinaiton host memory
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies an image object to system memory
|
||||
virtual bool readImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBuffer(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBufferRect(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to an image object
|
||||
virtual bool writeImage(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& srcRect, //!< Source rectangle
|
||||
const amd::BufferRect& dstRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies an image object to a buffer object
|
||||
virtual bool copyImageToBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
virtual bool copyBufferToImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies an image object to another image object
|
||||
virtual bool copyImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Fills a buffer memory with a pattern data
|
||||
virtual bool fillBuffer(
|
||||
device::Memory& memory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
size_t patternSize, //!< Pattern size
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Fills an image memory with a pattern data
|
||||
virtual bool fillImage(
|
||||
device::Memory& dstMemory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
protected:
|
||||
VirtualDevice& vDev_; //!< Virtual device object
|
||||
const amd::Device& dev_; //!< Physical device
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
HostBlitManager(const HostBlitManager&);
|
||||
|
||||
//! Disable operator=
|
||||
HostBlitManager& operator=(const HostBlitManager&);
|
||||
};
|
||||
|
||||
/*@}*/} // namespace device
|
||||
|
||||
#endif /*BLIT_HPP_*/
|
||||
@@ -0,0 +1,442 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
namespace device {
|
||||
|
||||
#define BLIT_KERNELS(...) #__VA_ARGS__
|
||||
|
||||
const char* BlitSourceCode = BLIT_KERNELS(
|
||||
\n
|
||||
__kernel void copyBufferToImage(
|
||||
__global uint* src,
|
||||
__write_only image2d_array_t dst,
|
||||
int4 srcOrigin,
|
||||
int4 dstOrigin,
|
||||
int4 size,
|
||||
int4 format,
|
||||
int4 pitch)
|
||||
{
|
||||
uint idxSrc;
|
||||
int4 coordsDst;
|
||||
uint4 pixel;
|
||||
__global uint* srcUInt = src;
|
||||
__global ushort* srcUShort = (__global ushort*)src;
|
||||
__global uchar* srcUChar = (__global uchar*)src;
|
||||
ushort tmpUShort;
|
||||
uint tmpUInt;
|
||||
|
||||
coordsDst.x = get_global_id(0);
|
||||
coordsDst.y = get_global_id(1);
|
||||
coordsDst.z = get_global_id(2);
|
||||
coordsDst.w = 0;
|
||||
|
||||
if ((coordsDst.x >= size.x) ||
|
||||
(coordsDst.y >= size.y) ||
|
||||
(coordsDst.z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
idxSrc = (coordsDst.z * pitch.y +
|
||||
coordsDst.y * pitch.x + coordsDst.x) *
|
||||
format.z + srcOrigin.x;
|
||||
|
||||
coordsDst.x += dstOrigin.x;
|
||||
coordsDst.y += dstOrigin.y;
|
||||
coordsDst.z += dstOrigin.z;
|
||||
|
||||
// Check components
|
||||
switch (format.x) {
|
||||
case 1:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
pixel.x = (uint)srcUChar[idxSrc];
|
||||
break;
|
||||
case 2:
|
||||
pixel.x = (uint)srcUShort[idxSrc];
|
||||
break;
|
||||
case 4:
|
||||
pixel.x = srcUInt[idxSrc];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
tmpUShort = srcUShort[idxSrc];
|
||||
pixel.x = (uint)(tmpUShort & 0xff);
|
||||
pixel.y = (uint)(tmpUShort >> 8);
|
||||
break;
|
||||
case 2:
|
||||
tmpUInt = srcUInt[idxSrc];
|
||||
pixel.x = (tmpUInt & 0xffff);
|
||||
pixel.y = (tmpUInt >> 16);
|
||||
break;
|
||||
case 4:
|
||||
pixel.x = srcUInt[idxSrc++];
|
||||
pixel.y = srcUInt[idxSrc];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
tmpUInt = srcUInt[idxSrc];
|
||||
pixel.x = tmpUInt & 0xff;
|
||||
pixel.y = (tmpUInt >> 8) & 0xff;
|
||||
pixel.z = (tmpUInt >> 16) & 0xff;
|
||||
pixel.w = (tmpUInt >> 24) & 0xff;
|
||||
break;
|
||||
case 2:
|
||||
tmpUInt = srcUInt[idxSrc++];
|
||||
pixel.x = tmpUInt & 0xffff;
|
||||
pixel.y = (tmpUInt >> 16);
|
||||
tmpUInt = srcUInt[idxSrc];
|
||||
pixel.z = tmpUInt & 0xffff;
|
||||
pixel.w = (tmpUInt >> 16);
|
||||
break;
|
||||
case 4:
|
||||
pixel.x = srcUInt[idxSrc++];
|
||||
pixel.y = srcUInt[idxSrc++];
|
||||
pixel.z = srcUInt[idxSrc++];
|
||||
pixel.w = srcUInt[idxSrc];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Write the final pixel
|
||||
write_imageui(dst, coordsDst, pixel);
|
||||
}
|
||||
\n
|
||||
__kernel void copyImageToBuffer(
|
||||
__read_only image2d_array_t src,
|
||||
__global uint* dstUInt,
|
||||
__global ushort* dstUShort,
|
||||
__global uchar* dstUChar,
|
||||
int4 srcOrigin,
|
||||
int4 dstOrigin,
|
||||
int4 size,
|
||||
int4 format,
|
||||
int4 pitch)
|
||||
{
|
||||
uint idxDst;
|
||||
int4 coordsSrc;
|
||||
uint4 texel;
|
||||
|
||||
coordsSrc.x = get_global_id(0);
|
||||
coordsSrc.y = get_global_id(1);
|
||||
coordsSrc.z = get_global_id(2);
|
||||
coordsSrc.w = 0;
|
||||
|
||||
if ((coordsSrc.x >= size.x) ||
|
||||
(coordsSrc.y >= size.y) ||
|
||||
(coordsSrc.z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
idxDst = (coordsSrc.z * pitch.y + coordsSrc.y * pitch.x +
|
||||
coordsSrc.x) * format.z + dstOrigin.x;
|
||||
|
||||
coordsSrc.x += srcOrigin.x;
|
||||
coordsSrc.y += srcOrigin.y;
|
||||
coordsSrc.z += srcOrigin.z;
|
||||
|
||||
texel = read_imageui(src, coordsSrc);
|
||||
|
||||
// Check components
|
||||
switch (format.x) {
|
||||
case 1:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
dstUChar[idxDst] = (uchar)texel.x;
|
||||
break;
|
||||
case 2:
|
||||
dstUShort[idxDst] = (ushort)texel.x;
|
||||
break;
|
||||
case 4:
|
||||
dstUInt[idxDst] = texel.x;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
dstUShort[idxDst] = (ushort)texel.x |
|
||||
((ushort)texel.y << 8);
|
||||
break;
|
||||
case 2:
|
||||
dstUInt[idxDst] = texel.x | (texel.y << 16);
|
||||
break;
|
||||
case 4:
|
||||
dstUInt[idxDst++] = texel.x;
|
||||
dstUInt[idxDst] = texel.y;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// Check size
|
||||
switch (format.y) {
|
||||
case 1:
|
||||
dstUInt[idxDst] = (uint)texel.x |
|
||||
(texel.y << 8) |
|
||||
(texel.z << 16) |
|
||||
(texel.w << 24);
|
||||
break;
|
||||
case 2:
|
||||
dstUInt[idxDst++] = texel.x | (texel.y << 16);
|
||||
dstUInt[idxDst] = texel.z | (texel.w << 16);
|
||||
break;
|
||||
case 4:
|
||||
dstUInt[idxDst++] = texel.x;
|
||||
dstUInt[idxDst++] = texel.y;
|
||||
dstUInt[idxDst++] = texel.z;
|
||||
dstUInt[idxDst] = texel.w;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
\n
|
||||
__kernel void copyImage(
|
||||
__read_only image2d_array_t src,
|
||||
__write_only image2d_array_t dst,
|
||||
int4 srcOrigin,
|
||||
int4 dstOrigin,
|
||||
int4 size)
|
||||
{
|
||||
int4 coordsDst;
|
||||
int4 coordsSrc;
|
||||
|
||||
coordsDst.x = get_global_id(0);
|
||||
coordsDst.y = get_global_id(1);
|
||||
coordsDst.z = get_global_id(2);
|
||||
coordsDst.w = 0;
|
||||
|
||||
if ((coordsDst.x >= size.x) ||
|
||||
(coordsDst.y >= size.y) ||
|
||||
(coordsDst.z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
coordsSrc = srcOrigin + coordsDst;
|
||||
coordsDst += dstOrigin;
|
||||
|
||||
uint4 texel;
|
||||
texel = read_imageui(src, coordsSrc);
|
||||
write_imageui(dst, coordsDst, texel);
|
||||
}
|
||||
\n
|
||||
__kernel void copyImage1DA(
|
||||
__read_only image2d_array_t src,
|
||||
__write_only image2d_array_t dst,
|
||||
int4 srcOrigin,
|
||||
int4 dstOrigin,
|
||||
int4 size)
|
||||
{
|
||||
int4 coordsDst;
|
||||
int4 coordsSrc;
|
||||
|
||||
coordsDst.x = get_global_id(0);
|
||||
coordsDst.y = get_global_id(1);
|
||||
coordsDst.z = get_global_id(2);
|
||||
coordsDst.w = 0;
|
||||
|
||||
if ((coordsDst.x >= size.x) ||
|
||||
(coordsDst.y >= size.y) ||
|
||||
(coordsDst.z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
coordsSrc = srcOrigin + coordsDst;
|
||||
coordsDst += dstOrigin;
|
||||
if (srcOrigin.w != 0) {
|
||||
coordsSrc.z = coordsSrc.y;
|
||||
coordsSrc.y = 0;
|
||||
}
|
||||
if (dstOrigin.w != 0) {
|
||||
coordsDst.z = coordsDst.y;
|
||||
coordsDst.y = 0;
|
||||
}
|
||||
|
||||
uint4 texel;
|
||||
texel = read_imageui(src, coordsSrc);
|
||||
write_imageui(dst, coordsDst, texel);
|
||||
}
|
||||
\n
|
||||
__kernel void copyBufferRect(
|
||||
__global uchar* src,
|
||||
__global uchar* dst,
|
||||
uint4 srcRect,
|
||||
uint4 dstRect,
|
||||
uint4 size)
|
||||
{
|
||||
uint x = (uint)get_global_id(0);
|
||||
uint y = (uint)get_global_id(1);
|
||||
uint z = (uint)get_global_id(2);
|
||||
|
||||
if ((x >= size.x) ||
|
||||
(y >= size.y) ||
|
||||
(z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint offsSrc = srcRect.z + x + y * srcRect.x + z * srcRect.y;
|
||||
uint offsDst = dstRect.z + x + y * dstRect.x + z * dstRect.y;
|
||||
|
||||
dst[offsDst] = src[offsSrc];
|
||||
}
|
||||
\n
|
||||
__kernel void copyBufferRectAligned(
|
||||
__global uint* src,
|
||||
__global uint* dst,
|
||||
uint4 srcRect,
|
||||
uint4 dstRect,
|
||||
uint4 size)
|
||||
{
|
||||
uint x = (uint)get_global_id(0);
|
||||
uint y = (uint)get_global_id(1);
|
||||
uint z = (uint)get_global_id(2);
|
||||
|
||||
if ((x >= size.x) ||
|
||||
(y >= size.y) ||
|
||||
(z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint offsSrc = srcRect.z + x + y * srcRect.x + z * srcRect.y;
|
||||
uint offsDst = dstRect.z + x + y * dstRect.x + z * dstRect.y;
|
||||
|
||||
if (size.w == 16) {
|
||||
__global uint4* src4 = (__global uint4*)src;
|
||||
__global uint4* dst4 = (__global uint4*)dst;
|
||||
dst4[offsDst] = src4[offsSrc];
|
||||
}
|
||||
else {
|
||||
dst[offsDst] = src[offsSrc];
|
||||
}
|
||||
}
|
||||
\n
|
||||
__kernel void copyBuffer(
|
||||
__global uchar* src,
|
||||
__global uchar* dst,
|
||||
int srcOrigin,
|
||||
int dstOrigin,
|
||||
uint size)
|
||||
{
|
||||
uint id = (uint)get_global_id(0);
|
||||
|
||||
if (id >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint offsSrc = id + srcOrigin;
|
||||
uint offsDst = id + dstOrigin;
|
||||
|
||||
dst[offsDst] = src[offsSrc];
|
||||
}
|
||||
\n
|
||||
__kernel void copyBufferAligned(
|
||||
__global uint* src,
|
||||
__global uint* dst,
|
||||
int srcOrigin,
|
||||
int dstOrigin,
|
||||
uint size,
|
||||
uint alignment)
|
||||
{
|
||||
uint id = (uint)get_global_id(0);
|
||||
|
||||
if (id >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint offsSrc = id + srcOrigin;
|
||||
uint offsDst = id + dstOrigin;
|
||||
|
||||
if (alignment == 16) {
|
||||
__global uint4* src4 = (__global uint4*)src;
|
||||
__global uint4* dst4 = (__global uint4*)dst;
|
||||
dst4[offsDst] = src4[offsSrc];
|
||||
}
|
||||
else {
|
||||
dst[offsDst] = src[offsSrc];
|
||||
}
|
||||
}
|
||||
\n
|
||||
__kernel void fillBuffer(
|
||||
__global uchar* bufUChar,
|
||||
__global uint* bufUInt,
|
||||
__constant uchar* pattern,
|
||||
uint patternSize,
|
||||
uint offset,
|
||||
uint size)
|
||||
{
|
||||
uint id = (uint)get_global_id(0);
|
||||
|
||||
if (id >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bufUInt) {
|
||||
__global uint* element = &bufUInt[offset + id * patternSize];
|
||||
__constant uint* pt = (__constant uint*)pattern;
|
||||
|
||||
for (uint i = 0; i < patternSize; ++i) {
|
||||
element[i] = pt[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
__global uchar* element = &bufUChar[offset + id * patternSize];
|
||||
|
||||
for (uint i = 0; i < patternSize; ++i) {
|
||||
element[i] = pattern[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
\n
|
||||
__kernel void fillImage(
|
||||
__write_only image2d_array_t image,
|
||||
float4 patternFLOAT4,
|
||||
int4 patternINT4,
|
||||
uint4 patternUINT4,
|
||||
int4 origin,
|
||||
int4 size,
|
||||
uint type)
|
||||
{
|
||||
int4 coords;
|
||||
|
||||
coords.x = get_global_id(0);
|
||||
coords.y = get_global_id(1);
|
||||
coords.z = get_global_id(2);
|
||||
coords.w = 0;
|
||||
|
||||
if ((coords.x >= size.x) ||
|
||||
(coords.y >= size.y) ||
|
||||
(coords.z >= size.z)) {
|
||||
return;
|
||||
}
|
||||
|
||||
coords += origin;
|
||||
|
||||
// Check components
|
||||
switch (type) {
|
||||
case 0:
|
||||
write_imagef(image, coords, patternFLOAT4);
|
||||
break;
|
||||
case 1:
|
||||
write_imagei(image, coords, patternINT4);
|
||||
break;
|
||||
case 2:
|
||||
write_imageui(image, coords, patternUINT4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
\n
|
||||
\n
|
||||
);
|
||||
|
||||
} // namespace device
|
||||
@@ -0,0 +1,213 @@
|
||||
//
|
||||
// Copyright 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/cpu/cpubinary.hpp"
|
||||
#include "device/cpu/cpudevice.hpp"
|
||||
#include "device/cpu/cpuprogram.hpp"
|
||||
#include "utils/versions.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
ClBinary::FeatureCheckResult
|
||||
ClBinary::checkFeatures()
|
||||
{
|
||||
/* Validate that all cpu features of loaded binary target (i.e. elf_target) exists in current target.
|
||||
* If some of elf_target features doesn't exist in current target we fail the build since we assume that elf LLVM-IR and binary are
|
||||
* target specific and can't be recompiled to current target*/
|
||||
uint16_t target = (uint16_t)dev().settings().cpuFeatures_;
|
||||
uint16_t elf_target;
|
||||
amd::OclElf::oclElfPlatform platform;
|
||||
if (!elfIn()->getTarget(elf_target, platform)){
|
||||
LogError("Loading OCL CPU binary: incorrect format");
|
||||
return ERROR;
|
||||
}
|
||||
uint64_t chip_options=0x0;
|
||||
if (platform == amd::OclElf::COMPLIB_PLATFORM) {
|
||||
// BIF 3.0
|
||||
uint32_t flag;
|
||||
if (!elfIn()->getFlags(flag)) {
|
||||
LogError("Loading OCL CPU binary: incorrect format");
|
||||
return ERROR;
|
||||
}
|
||||
aclTargetInfo tgtInfo = aclGetTargetInfoFromChipID(LP64_SWITCH("x86", "x86-64"), flag, NULL);
|
||||
chip_options = aclGetChipOptions(tgtInfo) ;
|
||||
if (((target & chip_options) != chip_options) ||
|
||||
((elf_target == EM_386) && (strcmp(LP64_SWITCH("x86", "x86-64"), "x86") != 0)) ||
|
||||
((elf_target == EM_X86_64) && (strcmp(LP64_SWITCH("x86", "x86-64"), "x86-64") != 0))){
|
||||
LogError("Loading OCL CPU binary: different target");
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// BIF 2.0
|
||||
if ((platform != amd::OclElf::CPU_PLATFORM) ||
|
||||
((target & elf_target) != elf_target)) {
|
||||
LogError("Loading OCL CPU binary: different target");
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
char* section;
|
||||
size_t sz;
|
||||
|
||||
/* If current target has more cpu features than the one for which the binary was (notice it must have all features as in elf_target
|
||||
* due to previous check), we can benefit from recompiling the LLVM-IR if exists in binary (if there are errors, ignore them !).*/
|
||||
if (((platform == amd::OclElf::CPU_PLATFORM) &&
|
||||
((target ^ elf_target) != 0)) ||
|
||||
((platform == amd::OclElf::COMPLIB_PLATFORM) &&
|
||||
((target ^ chip_options) != 0))) {
|
||||
if (elfIn_->getSection(amd::OclElf::LLVMIR, §ion, &sz)) {
|
||||
if ((section != NULL) && (sz > 0)) {
|
||||
// hasDLL being false to force recompiling
|
||||
RECOMPILE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::loadX86(Program& program, std::string& dllName, bool& hasDLL)
|
||||
{
|
||||
hasDLL = false;
|
||||
|
||||
std::string tempName = amd::Os::getTempFileName();
|
||||
|
||||
dllName = tempName
|
||||
+ "." WINDOWS_SWITCH("dll",MACOS_SWITCH("dyld","so"));
|
||||
|
||||
switch (checkFeatures()) {
|
||||
case ERROR:
|
||||
return false;
|
||||
case RECOMPILE:
|
||||
return true;
|
||||
case OK:
|
||||
// Fallthrough
|
||||
break;
|
||||
}
|
||||
|
||||
char* section;
|
||||
size_t sz;
|
||||
|
||||
if (!elfIn_->getSection(amd::OclElf::DLL, §ion, &sz)) {
|
||||
LogError("Loading OCL CPU binary: error occured!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((section == NULL) || (sz == 0)) {
|
||||
// hasDLL being false to force recompiling
|
||||
return true;
|
||||
}
|
||||
|
||||
std::fstream f;
|
||||
f.open(dllName.c_str(), (std::fstream::out | std::fstream::binary));
|
||||
|
||||
if (!f.is_open()) {
|
||||
#ifdef _WIN32
|
||||
amd::Os::unlink(tempName.c_str());
|
||||
#endif // _WIN32
|
||||
LogError("Loading OCL CPU binary: cannot open a file!");
|
||||
return false;
|
||||
}
|
||||
f.write(section, sz);
|
||||
f.close();
|
||||
|
||||
hasDLL = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::storeX86(Program& program, std::string& dllName)
|
||||
{
|
||||
std::fstream f;
|
||||
f.open(dllName.c_str(), (std::fstream::in | std::fstream::binary));
|
||||
if (!f.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f.seekg(0, std::fstream::end);
|
||||
size_t x86CodeSize = f.tellg();
|
||||
f.seekg(0, std::fstream::beg);
|
||||
|
||||
if (saveISA()) {
|
||||
char* x86Code = new char[x86CodeSize];
|
||||
f.read(x86Code, x86CodeSize);
|
||||
elfOut_->addSection(amd::OclElf::DLL, x86Code, x86CodeSize);
|
||||
delete [] x86Code;
|
||||
}
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::loadX86JIT(Program& program, bool& hasJITBinary)
|
||||
{
|
||||
hasJITBinary = false;
|
||||
|
||||
switch (checkFeatures()) {
|
||||
case ERROR:
|
||||
return false;
|
||||
case RECOMPILE:
|
||||
return true;
|
||||
case OK:
|
||||
// Fallthrough
|
||||
break;
|
||||
}
|
||||
|
||||
char* section;
|
||||
size_t sz;
|
||||
|
||||
if (!elfIn_->getSection(amd::OclElf::JITBINARY, §ion, &sz)) {
|
||||
LogError("Loading OCL CPU JIT binary: error occured!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((section == NULL) || (sz == 0)) {
|
||||
// force recompiling
|
||||
return true;
|
||||
}
|
||||
|
||||
program.setJITBinary(aclJITObjectImageCopy(section, sz));
|
||||
|
||||
hasJITBinary = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void checkDifference(const char* buf1, const char* buf2, size_t size) {
|
||||
for(size_t i = 0; i < size; ++i) {
|
||||
if(buf1[i] != buf2[i]) {
|
||||
printf("Index %d different",(int)i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool
|
||||
ClBinary::storeX86JIT(Program& program)
|
||||
{
|
||||
if (saveISA()) {
|
||||
aclJITObjectImage objectImage = program.getJITBinary();
|
||||
const char* x86CodePtr = aclJITObjectImageData(objectImage);
|
||||
size_t x86CodeSize = aclJITObjectImageSize(objectImage);
|
||||
|
||||
elfOut_->addSection(amd::OclElf::JITBINARY, x86CodePtr, x86CodeSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::storeX86Asm(const char* buffer, size_t size)
|
||||
{
|
||||
if (saveAS()) {
|
||||
elfOut_->addSection(amd::OclElf::ASTEXT, buffer, size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUBINARY_HPP_
|
||||
#define CPUBINARY_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/cpu/cpudevice.hpp"
|
||||
#include "elf/elf.hpp"
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
class Device;
|
||||
class Program;
|
||||
|
||||
//! \class CPU binary
|
||||
class ClBinary : public device::ClBinary
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
ClBinary(const Device& dev) : device::ClBinary(dev) {}
|
||||
|
||||
//! Destructor
|
||||
~ClBinary() {}
|
||||
|
||||
//! Loads x86 executable code
|
||||
bool loadX86(
|
||||
Program& prorgam, //!< CPU Program object
|
||||
std::string& dllName, //!< Dll name of the CPU binary
|
||||
bool& hasDLL //!< indicate if the OCL binary has DLL
|
||||
);
|
||||
|
||||
//! Stores x86 executable code
|
||||
bool storeX86(
|
||||
Program& program, //!< CPU Program object
|
||||
std::string& dllName //!< Dll name for the binary
|
||||
);
|
||||
|
||||
//! Loads x86 executable in-memory code
|
||||
bool loadX86JIT(
|
||||
Program& prorgam, //!< CPU Program object
|
||||
bool& hasJITBin //!< indicate if the OCL binary has JIT binary
|
||||
);
|
||||
|
||||
//! Stores x86 executable in-memory code
|
||||
bool storeX86JIT(
|
||||
Program& program //!< CPU Program object
|
||||
);
|
||||
|
||||
//! Set elf header information for CPU target
|
||||
bool setElfTarget() {
|
||||
uint32_t target = dev().settings().cpuFeatures_;
|
||||
assert (((0xFFFF8000 & target) == 0) && "ASIC target ID >= 2^15");
|
||||
uint16_t elf_target = (uint16_t)(0x7FFF & target);
|
||||
return elfOut()->setTarget(elf_target, amd::OclElf::CPU_PLATFORM);
|
||||
}
|
||||
|
||||
bool storeX86Asm(const char* buffer, size_t size);
|
||||
|
||||
private:
|
||||
|
||||
enum FeatureCheckResult {
|
||||
ERROR,
|
||||
RECOMPILE,
|
||||
OK
|
||||
};
|
||||
|
||||
FeatureCheckResult checkFeatures();
|
||||
|
||||
//! Disable default copy constructor
|
||||
ClBinary(const ClBinary&);
|
||||
|
||||
//! Disable default operator=
|
||||
ClBinary& operator=(const ClBinary&);
|
||||
|
||||
//! Returns the GPU device for this object
|
||||
const Device& dev() { return static_cast<const Device&>(dev_); }
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUBINARY_HPP_
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/cpu/cpubuiltins.hpp"
|
||||
#include "device/cpu/cpucommand.hpp"
|
||||
|
||||
#include <amdocl/cl_kernel.h>
|
||||
#include <cstdio> // for printf
|
||||
#include <stdarg.h>
|
||||
|
||||
#define BUF_SIZE_PRINTF 4095
|
||||
//In the current implementation of printf in gcc 4.5.2 runtime libraries,inf/infinity and nan are not supported
|
||||
//The [-]infinity value is printed as [-]1.#INF00
|
||||
//The [-]nan value is printed as [-]1.#INF00
|
||||
//bufOutUpdate converts the all printed instanced of [-]1.#INF00 to inf,and
|
||||
// all printed instanced of [-]1.#IND00 to nan
|
||||
void bufOutUpdate(std::string& sBufOut,const char* strToReplace,const char* strReplace)
|
||||
{
|
||||
size_t foundIdx = 0;
|
||||
while ((foundIdx = sBufOut.find(strToReplace,foundIdx)) != std::string::npos) {
|
||||
sBufOut.replace(foundIdx,strlen(strToReplace),strReplace,strlen(strReplace));
|
||||
foundIdx += 3;
|
||||
}
|
||||
}
|
||||
int cpuprintf(const char* format,...)
|
||||
{
|
||||
char cBufOut[BUF_SIZE_PRINTF];
|
||||
std::string sBufOut;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
//write to the buffer
|
||||
vsprintf(cBufOut,format,args);
|
||||
sBufOut = cBufOut;
|
||||
|
||||
//convert to correct infinity/nan representation
|
||||
bufOutUpdate(sBufOut,"1.#INF00","inf");
|
||||
bufOutUpdate(sBufOut,"1.#IND00","nan");
|
||||
bufOutUpdate(sBufOut,"1.#QNAN0","nan");
|
||||
int ret = amd::Os::printf("%s",sBufOut.c_str());
|
||||
fflush(stdout);
|
||||
va_end (args);
|
||||
return ret;
|
||||
}
|
||||
namespace cpu {
|
||||
|
||||
const clk_builtins_t
|
||||
Builtins::dispatchTable_ =
|
||||
{
|
||||
/* Synchronization functions */
|
||||
&WorkItem::barrier,
|
||||
/* AMD Only builtins: FIXME_lmoriche: remove or add an extension */
|
||||
NULL,
|
||||
cpuprintf
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef BUILTINS_HPP_
|
||||
#define BUILTINS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "amdocl/cl_kernel.h"
|
||||
|
||||
namespace cpu {
|
||||
|
||||
struct Builtins : public amd::AllStatic
|
||||
{
|
||||
static const clk_builtins_t dispatchTable_;
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif /*BUILTINS_HPP_*/
|
||||
@@ -0,0 +1,676 @@
|
||||
//
|
||||
// Copyright 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/cpu/cpucommand.hpp"
|
||||
#include "device/cpu/cpubuiltins.hpp"
|
||||
#include "device/cpu/cpudevice.hpp"
|
||||
#include "device/cpu/cputables.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/commandqueue.hpp"
|
||||
#include "platform/program.hpp"
|
||||
#include "platform/kernel.hpp"
|
||||
#include "platform/sampler.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "utils/util.hpp"
|
||||
|
||||
#include <amdocl/cl_kernel.h>
|
||||
|
||||
namespace cpu {
|
||||
|
||||
#define CPU_WORKER_THREAD_TOTAL_STACK_SIZE (CPU_WORKER_THREAD_STACK_SIZE + \
|
||||
CLK_PRIVATE_MEMORY_SIZE * (CPU_MAX_WORKGROUP_SIZE + 1))
|
||||
|
||||
WorkerThread::WorkerThread(const cpu::Device& device) :
|
||||
Thread("CPU Worker Thread", CPU_WORKER_THREAD_TOTAL_STACK_SIZE),
|
||||
queueLock_("WorkerThread::queueLock"), waitingOp_(0), terminated_(false)
|
||||
{
|
||||
localDataSize_ = (size_t) device.info().localMemSize_;
|
||||
localDataStorage_ = (address) amd::AlignedMemory::allocate(
|
||||
localDataSize_ + __CPU_SCRATCH_SIZE, sizeof(cl_long16)) +
|
||||
__CPU_SCRATCH_SIZE;
|
||||
|
||||
#if defined(__linux__) && defined(NUMA_SUPPORT)
|
||||
const nodemask_t* numaMask = device.getNumaMask();
|
||||
if (numaMask != NULL) {
|
||||
numa_bind(numaMask);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
WorkerThread::~WorkerThread()
|
||||
{
|
||||
guarantee(Thread::current() != this && "thread suicide!");
|
||||
amd::AlignedMemory::deallocate(localDataStorage_ - __CPU_SCRATCH_SIZE);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerThread::terminate()
|
||||
{
|
||||
terminated_ = true;
|
||||
|
||||
if (Thread::current() != this) {
|
||||
// FIXME_lmoriche: fix termination handshake
|
||||
while (state() < Thread::FINISHED) {
|
||||
flush();
|
||||
amd::Os::yield();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::enqueue(Operation& op)
|
||||
{
|
||||
while (waitingOp_ != 0) {
|
||||
amd::Os::yield();
|
||||
}
|
||||
op.clone(operation());
|
||||
++waitingOp_;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::loop()
|
||||
{
|
||||
baseWorkItemsStack_ = amd::alignDown(stackBase() -
|
||||
CPU_WORKER_THREAD_STACK_SIZE, CLK_PRIVATE_MEMORY_SIZE);
|
||||
#if defined(WIN32)
|
||||
amd::Os::touchStackPages(baseWorkItemsStack_, amd::Os::currentStackPtr());
|
||||
#endif // WINDOWS
|
||||
Operation *op = operation();
|
||||
|
||||
queueLock_.lock();
|
||||
while (true) {
|
||||
while (waitingOp_ == 0) {
|
||||
if (terminated_) {
|
||||
break;
|
||||
}
|
||||
queueLock_.wait();
|
||||
}
|
||||
if (terminated_) {
|
||||
break;
|
||||
}
|
||||
op->command().setStatus(CL_RUNNING);
|
||||
op->execute();
|
||||
op->cleanup();
|
||||
--waitingOp_;
|
||||
}
|
||||
queueLock_.unlock();
|
||||
}
|
||||
|
||||
void
|
||||
NativeFn::execute()
|
||||
{
|
||||
cl_int status = static_cast<amd::NativeFnCommand&>(command()).invoke();
|
||||
command().setStatus(status);
|
||||
}
|
||||
|
||||
static void
|
||||
nop() { /*Do nothing*/ }
|
||||
|
||||
|
||||
template <NDRangeKernelBatch::ExecutionNature NATURE,
|
||||
NDRangeKernelBatch::ExecutionOrder ORDER =
|
||||
NDRangeKernelBatch::ORDER_DEFAULT>
|
||||
class NDRangeKernelBatchMode : public NDRangeKernelBatch
|
||||
{
|
||||
private:
|
||||
void executeWorkGroup(WorkGroup& wg)
|
||||
{
|
||||
if (NATURE == NATURE_WG_LEVEL_EXEC) {
|
||||
wg.executeWorkItem();
|
||||
}
|
||||
else if ((NATURE == NATURE_1_WORK_ITEM) ||
|
||||
(wg.getNumWorkItems() == 1)) {
|
||||
wg.executeWorkItem();
|
||||
}
|
||||
else {
|
||||
wg.getBaseWorkItem()->setNext(&wg.getWorkerThread().mainFiber());
|
||||
if (NATURE == NATURE_WITHOUT_BARRIER) {
|
||||
wg.executeWithoutBarrier();
|
||||
}
|
||||
else { // NATURE == NATURE_WITH_BARRIER
|
||||
wg.executeWithBarrier();
|
||||
}
|
||||
}
|
||||
// Yield at the end of each workgroup to avoid starving GPU device
|
||||
amd::Os::yield();
|
||||
}
|
||||
|
||||
public:
|
||||
void executeMode(WorkGroup& wg)
|
||||
{
|
||||
const amd::NDRange& offset =
|
||||
static_cast<amd::NDRangeKernelCommand&>(command_).sizes().offset();
|
||||
WorkItem* workItem0 = wg.getBaseWorkItem();
|
||||
clk_builtins_t tableTask;
|
||||
size_t prevOpId = 0, opId = (size_t)-1;
|
||||
|
||||
if (NATURE == NATURE_1_WORK_ITEM) {
|
||||
tableTask = Builtins::dispatchTable_;
|
||||
|
||||
// If local size == 1 then barrier() becomes a nop.
|
||||
tableTask.barrier_ptr = (void (*)(cl_mem_fence_flags)) nop;
|
||||
workItem0->infoBlock().builtins = &tableTask;
|
||||
workItem0->setNext(&wg.getWorkerThread().mainFiber());
|
||||
}
|
||||
|
||||
while (getNextOperationId(opId)) {
|
||||
workItem0->incrementGroupId(groupIds_, offset, opId - prevOpId);
|
||||
uint workDims = workItem0->infoBlock().work_dim;
|
||||
size_t numWorkItems = workItem0->infoBlock().local_size[0] *
|
||||
(workDims >= 2 ? workItem0->infoBlock().local_size[1] : 1) *
|
||||
(workDims >= 3 ? workItem0->infoBlock().local_size[2] : 1);
|
||||
wg.setNumWorkItems(numWorkItems);
|
||||
if(numWorkItems == 1) {
|
||||
tableTask = Builtins::dispatchTable_;
|
||||
tableTask.barrier_ptr = (void (*)(cl_mem_fence_flags)) nop;
|
||||
workItem0->infoBlock().builtins = &tableTask;
|
||||
workItem0->setNext(&wg.getWorkerThread().mainFiber());
|
||||
executeWorkGroup(wg);
|
||||
tableTask.barrier_ptr = &WorkItem::barrier;
|
||||
} else {
|
||||
executeWorkGroup(wg);
|
||||
}
|
||||
prevOpId = opId;
|
||||
}
|
||||
|
||||
//#define DISABLE_TASK_STEALING
|
||||
#if !defined(DISABLE_TASK_STEALING) && 0
|
||||
size_t maxId = numCores_;
|
||||
size_t stolenId = coreId_ + 1;
|
||||
NDRangeKernelBatch* workingBatch = this;
|
||||
size_t numStolenIds = 1;
|
||||
const size_t maxStealingSize = 3;
|
||||
const size_t minAdaptiveStealingDiff = numCores_ * maxStealingSize;
|
||||
|
||||
while (true) {
|
||||
for (; stolenId < maxId; ++stolenId) {
|
||||
WorkerThread* worker = virtualDevice_.getWorkerThread(stolenId);
|
||||
|
||||
// In case were we have less operations than Worker Threads
|
||||
if (worker->isOperationValid()) {
|
||||
workingBatch = static_cast<NDRangeKernelBatch*>(
|
||||
worker->operation());
|
||||
|
||||
numStolenIds =
|
||||
workingBatch->getNextOperationIds(opId, numStolenIds);
|
||||
if (numStolenIds > 0) {
|
||||
do {
|
||||
for (size_t i = 0; i < numStolenIds; ++i) {
|
||||
workItem0->setGroupId(groupIds_, offset, opId);
|
||||
executeWorkGroup(wg);
|
||||
opId += numCores_;
|
||||
}
|
||||
|
||||
// adaptive stealing
|
||||
if (numWorkGroups_ - opId > minAdaptiveStealingDiff) {
|
||||
numStolenIds = maxStealingSize;
|
||||
}
|
||||
else {
|
||||
while (workingBatch->getNextOperationId(opId)) {
|
||||
workItem0->setGroupId(groupIds_, offset, opId);
|
||||
executeWorkGroup(wg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
numStolenIds = workingBatch->getNextOperationIds(
|
||||
opId, numStolenIds);
|
||||
} while (numStolenIds > 0);
|
||||
}
|
||||
numStolenIds = 1;
|
||||
}
|
||||
} // for (stolenId..maxId)
|
||||
|
||||
if (stolenId == coreId_) {
|
||||
break;
|
||||
}
|
||||
|
||||
stolenId = 0;
|
||||
maxId = coreId_;
|
||||
} // while (true)
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline bool
|
||||
NDRangeKernelBatch::getNextOperationId(size_t& opId)
|
||||
{
|
||||
if (currentOpId_ >= numWorkGroups_) {
|
||||
return false;
|
||||
}
|
||||
opId = amd::AtomicOperation::add(numCores_, ¤tOpId_);
|
||||
return opId < numWorkGroups_;
|
||||
}
|
||||
|
||||
|
||||
inline size_t
|
||||
NDRangeKernelBatch::getNextOperationIds(size_t& opId, size_t count)
|
||||
{
|
||||
size_t topId = numCores_ * count;
|
||||
if (currentOpId_ >= numWorkGroups_) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
opId = amd::AtomicOperation::add(topId, ¤tOpId_);
|
||||
const size_t numWorkGroups = numWorkGroups_;
|
||||
if (opId >= numWorkGroups) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
topId += opId;
|
||||
if (topId >= (numWorkGroups + numCores_)) {
|
||||
count -= (topId - numWorkGroups) / numCores_;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Process the parameters, allocate LDS.
|
||||
bool
|
||||
NDRangeKernelBatch::patchParameters(
|
||||
const cpu::Kernel& cpuKernel,
|
||||
address params,
|
||||
address& localMemPtr,
|
||||
const address localMemLimit,
|
||||
size_t localMemSize) const
|
||||
{
|
||||
amd::NDRangeKernelCommand& command =
|
||||
static_cast<amd::NDRangeKernelCommand&>(command_);
|
||||
|
||||
const amd::Device& device = command.queue()->device();
|
||||
|
||||
const amd::Kernel& kernel = command.kernel();
|
||||
const amd::KernelSignature& signature = kernel.signature();
|
||||
const amd::KernelParameters& kernelParam = kernel.parameters();
|
||||
|
||||
const_address cmdParams = command.parameters();
|
||||
|
||||
unsigned effectiveOffset = 0;
|
||||
|
||||
// DD -- on CPU device, real effective offset is NATIVELY aligned
|
||||
// Here all source arguments are in place, so we're safe just iterating
|
||||
for (size_t i = 0; i < signature.numParameters(); ++i) {
|
||||
const amd::KernelParameterDescriptor& desc = signature.at(i);
|
||||
const void* cmdParam = cmdParams + desc.offset_;
|
||||
void *param;
|
||||
size_t prmSize = cpuKernel.getArgSize(i);
|
||||
|
||||
// Align i'th parameter on multiple of its size. Parameter size is power of 2.
|
||||
size_t alignment = cpuKernel.getArgAlignment(i);
|
||||
effectiveOffset = amd::alignUp(effectiveOffset, std::min(alignment, size_t(16)));
|
||||
param = params + effectiveOffset;
|
||||
|
||||
if (desc.size_ == 0) {
|
||||
// __local memory parameter
|
||||
localMemPtr = amd::alignUp(localMemPtr, sizeof(cl_long16));
|
||||
|
||||
size_t length = *static_cast<const size_t*>(cmdParam);
|
||||
*static_cast<void**>(param) = localMemPtr;
|
||||
localMemPtr += length;
|
||||
|
||||
if (localMemPtr > localMemLimit) {
|
||||
command.setException(CL_MEM_OBJECT_ALLOCATION_FAILURE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (desc.type_ == T_POINTER) {
|
||||
// __global memory parameter
|
||||
cl_mem_object_type pointer_type = CL_MEM_OBJECT_BUFFER;
|
||||
if (kernelParam.boundToSvmPointer(device, cmdParams, i)) {
|
||||
*reinterpret_cast<void**>(param) =
|
||||
*reinterpret_cast<void* const *>(cmdParam);
|
||||
}
|
||||
else {
|
||||
void* hostMemPtr = NULL;
|
||||
amd::Memory* memArg =
|
||||
*reinterpret_cast<amd::Memory* const *>(cmdParam);
|
||||
if (memArg != NULL) {
|
||||
hostMemPtr = memArg->getHostMem();
|
||||
if (hostMemPtr == NULL) {
|
||||
command.setException(CL_MEM_OBJECT_ALLOCATION_FAILURE);
|
||||
return false;
|
||||
}
|
||||
pointer_type = memArg->getType();
|
||||
}
|
||||
// For images on CPU devices, pass "struct {int4 p0; int4 p1}".
|
||||
// That allows an obvious implementation for
|
||||
// __amdil_get_image[23]d_params[01].
|
||||
// That makes the rest of the .bc implementation for
|
||||
// images relatively straight forward.
|
||||
if (pointer_type == CL_MEM_OBJECT_IMAGE1D ||
|
||||
pointer_type == CL_MEM_OBJECT_IMAGE2D ||
|
||||
pointer_type == CL_MEM_OBJECT_IMAGE3D ||
|
||||
pointer_type == CL_MEM_OBJECT_IMAGE1D_ARRAY ||
|
||||
pointer_type == CL_MEM_OBJECT_IMAGE1D_BUFFER ||
|
||||
pointer_type == CL_MEM_OBJECT_IMAGE2D_ARRAY) {
|
||||
amd::Image::Impl& impl = memArg->asImage()->getImpl();
|
||||
impl.reserved_ = hostMemPtr;
|
||||
*reinterpret_cast<void**>(param) = (void*)&impl;
|
||||
} else {
|
||||
*reinterpret_cast<void**>(param) = hostMemPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (desc.type_ == T_SAMPLER) {
|
||||
// Switch from an Amd::Sampler to the 32bit integer
|
||||
// variable that is a clk_sampler.
|
||||
amd::Sampler* samplerArg =
|
||||
*reinterpret_cast<amd::Sampler* const *>(cmdParam);
|
||||
*reinterpret_cast<uint32_t*>(param) = (uint32_t)samplerArg->state();
|
||||
}
|
||||
else {
|
||||
::memcpy(param, cmdParam, desc.size_);
|
||||
}
|
||||
|
||||
effectiveOffset += cpuKernel.getArgSize(i);
|
||||
}
|
||||
|
||||
localMemPtr = amd::alignUp(localMemPtr, sizeof(cl_long16));
|
||||
if ((localMemPtr + localMemSize) > localMemLimit) {
|
||||
command.setException(CL_MEM_OBJECT_ALLOCATION_FAILURE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
NDRangeKernelBatch::execute()
|
||||
{
|
||||
amd::NDRangeKernelCommand& command =
|
||||
static_cast<amd::NDRangeKernelCommand&>(command_);
|
||||
|
||||
const cpu::Kernel& kernel = static_cast<const cpu::Kernel&>(
|
||||
*command.kernel().getDeviceKernel(command.queue()->device()));
|
||||
|
||||
WorkerThread& thread = *WorkerThread::current();
|
||||
|
||||
const size_t numWorkItems = command.sizes().local().product();
|
||||
|
||||
address params = thread.baseWorkItemsStack();
|
||||
address localMemPtr = thread.localDataStorage();
|
||||
if (!patchParameters(kernel,
|
||||
params, localMemPtr, localMemPtr + thread.localDataSize(),
|
||||
kernel.workGroupInfo()->localMemSize_)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkItem* workItem0 = ::new((WorkItem*)params - 1) WorkItem(
|
||||
command.sizes(), localMemPtr);
|
||||
|
||||
WorkGroup wg(command, kernel, thread, params, workItem0, numWorkItems);
|
||||
|
||||
if (numWorkItems == 1) {
|
||||
static_cast<NDRangeKernelBatchMode<NATURE_1_WORK_ITEM>*>(this)->
|
||||
executeMode(wg);
|
||||
}
|
||||
else if (kernel.hasBarrier()) {
|
||||
static_cast<NDRangeKernelBatchMode<NATURE_WITH_BARRIER>*>(this)->
|
||||
executeMode(wg);
|
||||
}
|
||||
else {
|
||||
static_cast<NDRangeKernelBatchMode<NATURE_WITHOUT_BARRIER>*>(this)->
|
||||
executeMode(wg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkGroup::executeWorkItem()
|
||||
{
|
||||
callKernel((kernelentrypoint_t)kernel_.getEntryPoint(), workItem0_->nativeStackPtr());
|
||||
}
|
||||
|
||||
void
|
||||
WorkGroup::executeWithBarrier()
|
||||
{
|
||||
kernelentrypoint_t entryPoint = (kernelentrypoint_t)kernel_.getEntryPoint();
|
||||
|
||||
workingFiber_ = workItem0_;
|
||||
address workGroupStackPtr = workItem0_->nativeStackPtr();
|
||||
|
||||
// Save the current stack context in case we execute a barrier.
|
||||
volatile size_t threadCounter = 0;
|
||||
bool barrier = !thread_.mainFiber().save();
|
||||
|
||||
size_t tid = threadCounter++;
|
||||
WorkItem* workItem = (WorkItem*)((char*) workItem0_
|
||||
- tid * CLK_PRIVATE_MEMORY_SIZE);
|
||||
|
||||
if (barrier) {
|
||||
WorkItem* prev = (WorkItem*)((char*) workItem
|
||||
+ CLK_PRIVATE_MEMORY_SIZE);
|
||||
|
||||
WINDOWS_ONLY(amd::Os::touchStackPages(
|
||||
(address) (workItem + 1), (address) prev));
|
||||
::memcpy(workItem, prev, sizeof(WorkItem));
|
||||
|
||||
clk_thread_info_block_t& tib = workItem->infoBlock();
|
||||
++tib.local_id[0];
|
||||
if (unlikely(tib.local_id[0] >= tib.local_size[0])) {
|
||||
//
|
||||
// Compiling for Windows 64bit (only in release) introduces a bug,
|
||||
// which uses the same register for saving threadCounter and the
|
||||
// 0 value. Therefore "tib.local_id[i] = 0" was actually translated
|
||||
// to "tib.local_id[0] = threadCounter". To avoid this issue, and
|
||||
// still be able to store a 0 into tib.local_id[i], we trick the
|
||||
// compiler, by using the value in tib.local_id[3], which is always
|
||||
// initialized to 0.
|
||||
//
|
||||
tib.local_id[0] = tib.local_id[3];
|
||||
|
||||
++tib.local_id[1];
|
||||
if (unlikely(tib.local_id[1] >= tib.local_size[1])) {
|
||||
tib.local_id[1] = tib.local_id[3];
|
||||
|
||||
++tib.local_id[2];
|
||||
}
|
||||
}
|
||||
|
||||
// Link the previous workitem to this one.
|
||||
prev->setNext(workItem);
|
||||
// If this is the last workitem, complete the ring.
|
||||
if (tid >= numWorkItems_ - 1) {
|
||||
workItem->setNext(workItem0_);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute thread0
|
||||
|
||||
address workItemStackPtr = workItem->nativeStackPtr();
|
||||
callKernelProtectedReturn(entryPoint, workItemStackPtr);
|
||||
|
||||
// Check if thread0 executed a barrier()
|
||||
if (threadCounter > 1) {
|
||||
workItem = (WorkItem*)workingFiber_;
|
||||
workingFiber_ = workingFiber_->next();
|
||||
|
||||
tid = ((address)workItem0_ - (address)workItem)
|
||||
/ CLK_PRIVATE_MEMORY_SIZE;
|
||||
if (tid == (numWorkItems_ - 1)) {
|
||||
// If we get here, we are done!
|
||||
return;
|
||||
}
|
||||
if (workItem->next() == &thread_.mainFiber()) {
|
||||
// Detected a deadlock
|
||||
command_.setException(CL_INVALID_KERNEL);
|
||||
return;
|
||||
}
|
||||
|
||||
// Schedule the next workitem.
|
||||
workItem->next()->restore();
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// Execute thread1...threadN
|
||||
callKernelRange(entryPoint, workItemStackPtr, workItem->infoBlock());
|
||||
}
|
||||
|
||||
void
|
||||
WorkGroup::executeWithoutBarrier()
|
||||
{
|
||||
kernelentrypoint_t entryPoint = (kernelentrypoint_t)kernel_.getEntryPoint();
|
||||
address workItemStackPtr = workItem0_->nativeStackPtr();
|
||||
|
||||
// Execute thread0
|
||||
callKernel(entryPoint, workItemStackPtr);
|
||||
|
||||
// Execute thread1...threadN
|
||||
callKernelRange(entryPoint, workItemStackPtr, workItem0_->infoBlock());
|
||||
}
|
||||
|
||||
void
|
||||
WorkGroup::callKernelRange(kernelentrypoint_t entryPoint,
|
||||
address stackPtr,
|
||||
clk_thread_info_block_t& tib)
|
||||
{
|
||||
while (true) {
|
||||
++tib.local_id[0];
|
||||
if (unlikely(tib.local_id[0] >= tib.local_size[0])) {
|
||||
tib.local_id[0] = 0;
|
||||
|
||||
++tib.local_id[1];
|
||||
if (unlikely(tib.local_id[1] >= tib.local_size[1])) {
|
||||
tib.local_id[1] = 0;
|
||||
|
||||
++tib.local_id[2];
|
||||
if (unlikely(tib.local_id[2] >= tib.local_size[2])) {
|
||||
tib.local_id[2] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callKernel(entryPoint, stackPtr);
|
||||
}
|
||||
}
|
||||
|
||||
WorkItem::WorkItem(const amd::NDRangeContainer& sizes, void* localMemPtr)
|
||||
{
|
||||
const amd::NDRange& local = sizes.local();
|
||||
const amd::NDRange& global = sizes.global();
|
||||
const amd::NDRange& offset = sizes.offset();
|
||||
const size_t dims = sizes.dimensions();
|
||||
|
||||
tib_.builtins = &Builtins::dispatchTable_;
|
||||
tib_.work_dim = (cl_uint) sizes.dimensions();
|
||||
tib_.local_mem_base = localMemPtr;
|
||||
tib_.table_base = (const void *)cpuTables;
|
||||
for (size_t i = 0; i < dims; ++i) {
|
||||
tib_.global_offset[i] = offset[i];
|
||||
tib_.global_size[i] = global[i];
|
||||
tib_.local_size[i] = local[i];
|
||||
tib_.enqueued_local_size[i] = local[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.group_id[i] = 0;
|
||||
}
|
||||
// Fill the remaining dimensions.
|
||||
for (size_t i = dims; i < sizeof(tib_.global_size)/sizeof(size_t); ++i) {
|
||||
tib_.global_offset[i] = 0;
|
||||
tib_.global_size[i] = 1;
|
||||
tib_.local_size[i] = 1;
|
||||
tib_.enqueued_local_size[i] = 1;
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.group_id[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYSINLINE void
|
||||
WorkItem::setGroupId(
|
||||
const amd::NDRange& rangeLimits,
|
||||
const amd::NDRange& offset,
|
||||
size_t n)
|
||||
{
|
||||
const size_t dims = rangeLimits.dimensions();
|
||||
for (size_t i = 0; i < dims; ++i) {
|
||||
size_t lim = rangeLimits[i];
|
||||
size_t& val = tib_.group_id[i];
|
||||
val = n;
|
||||
if (n < lim) {
|
||||
tib_.global_offset[i] =
|
||||
offset[i] + val * tib_.enqueued_local_size[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.local_size[i] =
|
||||
std::min(tib_.enqueued_local_size[i],
|
||||
tib_.global_size[i] - (val * tib_.enqueued_local_size[i]));
|
||||
|
||||
++i;
|
||||
for (; i < dims; ++i) {
|
||||
tib_.global_offset[i] = offset[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.group_id[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
n /= lim;
|
||||
val -= n * lim;
|
||||
tib_.global_offset[i] =
|
||||
offset[i] + val * tib_.enqueued_local_size[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.local_size[i] =
|
||||
std::min(tib_.enqueued_local_size[i],
|
||||
tib_.global_size[i] - (val * tib_.enqueued_local_size[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYSINLINE void
|
||||
WorkItem::incrementGroupId(
|
||||
const amd::NDRange& rangeLimits,
|
||||
const amd::NDRange& offset,
|
||||
size_t n)
|
||||
{
|
||||
const size_t dims = rangeLimits.dimensions();
|
||||
for (size_t i = 0; i < dims; ++i) {
|
||||
size_t lim = rangeLimits[i];
|
||||
size_t& val = tib_.group_id[i];
|
||||
val += n;
|
||||
if (val < lim) {
|
||||
tib_.global_offset[i] =
|
||||
offset[i] + val * tib_.enqueued_local_size[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.local_size[i] =
|
||||
std::min(tib_.enqueued_local_size[i],
|
||||
tib_.global_size[i] - (val * tib_.enqueued_local_size[i]));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
n = val / lim;
|
||||
val -= n * lim;
|
||||
tib_.global_offset[i] =
|
||||
offset[i] + val * tib_.enqueued_local_size[i];
|
||||
tib_.local_id[i] = 0;
|
||||
tib_.local_size[i] =
|
||||
std::min(tib_.enqueued_local_size[i],
|
||||
tib_.global_size[i] - (val * tib_.enqueued_local_size[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkItem::barrier(cl_mem_fence_flags flags)
|
||||
{
|
||||
WorkItem* workItem = WorkItem::current();
|
||||
workItem->swap(workItem->next());
|
||||
}
|
||||
|
||||
void Operation::cleanup()
|
||||
{
|
||||
cl_int lastException = command().exception();
|
||||
cl_int status = (lastException != 0) ? lastException : CL_COMPLETE;
|
||||
|
||||
Counter* counter = reinterpret_cast<Counter*>(command().data());
|
||||
if (counter == NULL) {
|
||||
command().setStatus(status);
|
||||
}
|
||||
else if (counter->decrement() == 0) {
|
||||
counter->event().setStatus(status);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
@@ -0,0 +1,425 @@
|
||||
//
|
||||
// Copyright 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef OPERATION_HPP_
|
||||
#define OPERATION_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/cpu/cpudevice.hpp"
|
||||
#include "device/cpu/cpukernel.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "amdocl/cl_kernel.h"
|
||||
#include "device/cpu/ring.hpp"
|
||||
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
#include <setjmp.h>
|
||||
#endif // ATI_ARCH_ARM
|
||||
|
||||
namespace cpu {
|
||||
|
||||
/*! \addtogroup CPU
|
||||
* @{
|
||||
*
|
||||
* \addtogroup CPUExec Execution environment
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! A saved stack context
|
||||
class StackContext : public amd::StackObject
|
||||
{
|
||||
private:
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
jmp_buf env_;
|
||||
#elif defined(_WIN64)
|
||||
intptr_t __declspec(align(16)) regs_[32];
|
||||
#else // !_WIN64
|
||||
intptr_t regs_[LP64_SWITCH(6,8)];
|
||||
#endif // !_WIN64
|
||||
|
||||
public:
|
||||
//! Save the stack context. Return 0 if returning directly.
|
||||
inline intptr_t setjmp();
|
||||
|
||||
//! Restore the stack context
|
||||
inline void longjmp(intptr_t val) const;
|
||||
};
|
||||
|
||||
//! A thread fiber
|
||||
class Fiber : public amd::StackObject
|
||||
{
|
||||
private:
|
||||
//! Next fiber in the thread.
|
||||
Fiber* next_;
|
||||
|
||||
//! This fiber's saved state.
|
||||
StackContext context_;
|
||||
|
||||
public:
|
||||
//! Construct a new Fiber
|
||||
Fiber() : next_(NULL) { }
|
||||
|
||||
//! Return the next fiber in the current thread.
|
||||
const Fiber* next() const { return next_; }
|
||||
//! Set the next fiber in the current thread.
|
||||
void setNext(Fiber* next) { next_ = next; }
|
||||
|
||||
//! Save the state of this fiber. Return true if directly returning.
|
||||
ALWAYSINLINE bool save() { return context_.setjmp() == 0; }
|
||||
//! Restore this fiber from the saved context.
|
||||
void restore() const { context_.longjmp(1); }
|
||||
|
||||
//! Switch to the given fiber.
|
||||
void swap(const Fiber* fiber) { if (save()) { fiber->restore(); } }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//! A CPU core operation (enqueued in the worker thread queue)
|
||||
class Operation : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! An atomic counter
|
||||
class Counter
|
||||
{
|
||||
// FIXME_lmoriche: recycle the counters, implement a thread local pool.
|
||||
private:
|
||||
amd::Event& event_;
|
||||
//! The atomic counter value.
|
||||
amd::Atomic<size_t> counter_;
|
||||
|
||||
public:
|
||||
//! Initialize the counter with the given initial value.
|
||||
Counter(amd::Event& event, size_t initialValue) :
|
||||
event_(event), counter_(initialValue) { }
|
||||
//! Return the event associated with this counter.
|
||||
amd::Event& event() { return event_; }
|
||||
//! Decrement the counter and return the new value.
|
||||
size_t decrement() { return --counter_; }
|
||||
};
|
||||
|
||||
protected:
|
||||
amd::Command& command_;
|
||||
|
||||
public:
|
||||
Operation(amd::Command& command) : command_(command)
|
||||
{ }
|
||||
|
||||
virtual ~Operation() {};
|
||||
|
||||
virtual void clone(Operation* buf) = 0;
|
||||
|
||||
void cleanup();
|
||||
|
||||
amd::Command& command() { return command_;}
|
||||
|
||||
virtual void execute() = 0;
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* \defgroup CPUOperations Operations
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! A work item instance
|
||||
class WorkItem : public Fiber
|
||||
{
|
||||
private:
|
||||
//! Thread info block (must be the last field).
|
||||
clk_thread_info_block_t tib_;
|
||||
|
||||
private:
|
||||
//! Cannot be deleted (allocated with placement new).
|
||||
void operator delete(void*) { ShouldNotCallThis(); }
|
||||
|
||||
public:
|
||||
//! Initialize this workgroup.
|
||||
WorkItem(const amd::NDRangeContainer& size, void* localMemPtr);
|
||||
|
||||
//! Return the current WorkItem (based of the current stack pointer).
|
||||
static WorkItem* current() {
|
||||
return (WorkItem*)amd::alignUp((intptr_t) amd::Os::currentStackPtr(),
|
||||
CLK_PRIVATE_MEMORY_SIZE) - 1;
|
||||
}
|
||||
|
||||
clk_thread_info_block_t& infoBlock() { return tib_; }
|
||||
|
||||
//! Return the native stack pointer base for this workitem.
|
||||
address nativeStackPtr() const {
|
||||
address newSp = amd::alignDown((address) this - CPUKERNEL_STACK_ALIGN,
|
||||
CPUKERNEL_STACK_ALIGN);
|
||||
WINDOWS_ONLY(NOT_WIN64(newSp += sizeof(void*)));
|
||||
return newSp;
|
||||
}
|
||||
|
||||
//! These functions are mapping "n" from 1d index to the required dimension
|
||||
inline void setGroupId(
|
||||
const amd::NDRange& rangeLimits,
|
||||
const amd::NDRange& offset,
|
||||
size_t n);
|
||||
inline void incrementGroupId(
|
||||
const amd::NDRange& rangeLimits,
|
||||
const amd::NDRange& offset,
|
||||
size_t n);
|
||||
|
||||
//! Execute a thread synchronization barrier.
|
||||
static void barrier(cl_mem_fence_flags flags);
|
||||
};
|
||||
|
||||
typedef void (*kernelentrypoint_t)(const void*);
|
||||
|
||||
//! Execute a workgroup (work-items).
|
||||
class WorkGroup
|
||||
{
|
||||
private:
|
||||
amd::NDRangeKernelCommand& command_;
|
||||
const cpu::Kernel& kernel_;
|
||||
WorkerThread& thread_;
|
||||
address params_;
|
||||
WorkItem* const workItem0_;
|
||||
const Fiber* workingFiber_;
|
||||
size_t numWorkItems_;
|
||||
|
||||
public:
|
||||
WorkGroup(
|
||||
amd::NDRangeKernelCommand& parent,
|
||||
const cpu::Kernel& kernel,
|
||||
WorkerThread& thread,
|
||||
address params,
|
||||
WorkItem* workItem0,
|
||||
const size_t numWorkItems) :
|
||||
command_(parent),
|
||||
kernel_(kernel),
|
||||
thread_(thread),
|
||||
params_(params),
|
||||
workItem0_(workItem0),
|
||||
numWorkItems_(numWorkItems)
|
||||
{ }
|
||||
|
||||
WorkItem* getBaseWorkItem() { return workItem0_; }
|
||||
WorkerThread& getWorkerThread() { return thread_; }
|
||||
|
||||
void executeWorkItem(); // In case of 1 WorkItem
|
||||
void executeWithBarrier();
|
||||
void executeWithoutBarrier();
|
||||
|
||||
void setNumWorkItems(size_t workItems) { numWorkItems_ = workItems; }
|
||||
size_t getNumWorkItems() { return numWorkItems_; }
|
||||
private:
|
||||
void callKernelRange(
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr,
|
||||
clk_thread_info_block_t& tib);
|
||||
inline void callKernel(
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr);
|
||||
inline void callKernelProtectedReturn(
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr);
|
||||
};
|
||||
|
||||
class NDRangeKernelBatch : public Operation
|
||||
{
|
||||
protected:
|
||||
size_t coreId_;
|
||||
const size_t numWorkGroups_;
|
||||
const size_t numCores_;
|
||||
volatile size_t currentOpId_;
|
||||
const amd::NDRange groupIds_; //!< Number of groups in each dimensions
|
||||
VirtualCPU& virtualDevice_;
|
||||
|
||||
public:
|
||||
enum ExecutionOrder {
|
||||
ORDER_DEFAULT,
|
||||
ORDER_ROUND_ROBIN = ORDER_DEFAULT,
|
||||
//ORDER_LINEAR
|
||||
};
|
||||
|
||||
enum ExecutionNature {
|
||||
NATURE_WITH_BARRIER,
|
||||
NATURE_WITHOUT_BARRIER,
|
||||
NATURE_1_WORK_ITEM,
|
||||
NATURE_WG_LEVEL_EXEC
|
||||
};
|
||||
|
||||
NDRangeKernelBatch(
|
||||
amd::NDRangeKernelCommand& parent,
|
||||
VirtualCPU& virtualDevice,
|
||||
const amd::NDRange& groupIds, size_t numCores) :
|
||||
Operation(parent),
|
||||
coreId_(0),
|
||||
numWorkGroups_(groupIds.product()),
|
||||
numCores_(numCores),
|
||||
currentOpId_(0),
|
||||
groupIds_(groupIds),
|
||||
virtualDevice_(virtualDevice)
|
||||
{ }
|
||||
|
||||
virtual void clone(Operation* buf)
|
||||
{
|
||||
::new(buf) NDRangeKernelBatch(static_cast<amd::NDRangeKernelCommand&>(command_),
|
||||
virtualDevice_, groupIds_, numCores_);
|
||||
static_cast<NDRangeKernelBatch*>(buf)->setCoreId(coreId_);
|
||||
}
|
||||
|
||||
virtual void execute();
|
||||
|
||||
void setCoreId(size_t coreId) { coreId_ = coreId; currentOpId_ = coreId; }
|
||||
|
||||
inline bool getNextOperationId(size_t& opId);
|
||||
inline size_t getNextOperationIds(size_t& opId, size_t count);
|
||||
|
||||
private:
|
||||
bool patchParameters(
|
||||
const cpu::Kernel& kernel,
|
||||
address params,
|
||||
address& localMemPtr,
|
||||
const address localMemLimit,
|
||||
size_t localMemSize) const;
|
||||
};
|
||||
|
||||
class NativeFn : public Operation
|
||||
{
|
||||
public:
|
||||
NativeFn(amd::NativeFnCommand& parent) : Operation(parent)
|
||||
{ }
|
||||
|
||||
virtual void clone(Operation* buf)
|
||||
{
|
||||
::new(buf) NativeFn(static_cast<amd::NativeFnCommand&>(command_));
|
||||
}
|
||||
|
||||
virtual void execute();
|
||||
};
|
||||
#ifndef MAX
|
||||
#define MAX(x,y) ((x)>=(y) ?(x) : (y))
|
||||
#endif //MAX
|
||||
|
||||
#define MAX_OPERATION_ALLOC_SIZE (MAX(sizeof(NDRangeKernelBatch), sizeof(NativeFn)))
|
||||
|
||||
//! A thread bound to a cpu core.
|
||||
class WorkerThread : public amd::Thread
|
||||
{
|
||||
private:
|
||||
Fiber mainFiber_; //!< main fiber for this worker thread.
|
||||
|
||||
amd::Monitor queueLock_; //!< lock protecting the queue.
|
||||
volatile int waitingOp_;
|
||||
bool terminated_; //!< true if the thread is shutting down.
|
||||
|
||||
//! Local memory storage
|
||||
address localDataStorage_;
|
||||
//! Size of the local memory.
|
||||
size_t localDataSize_;
|
||||
|
||||
char operation_[MAX_OPERATION_ALLOC_SIZE];
|
||||
|
||||
address baseWorkItemsStack_;
|
||||
private:
|
||||
//! Awaits operations and execute them as they become ready.
|
||||
void loop();
|
||||
|
||||
public:
|
||||
//! Construct a new WorkerThread.
|
||||
WorkerThread(const cpu::Device& device);
|
||||
//! Destroy the worker thread.
|
||||
virtual ~WorkerThread();
|
||||
//! Cleanup the thread before termination.
|
||||
bool terminate();
|
||||
|
||||
//! Return the main fiber for this thread.
|
||||
Fiber& mainFiber() { return mainFiber_; }
|
||||
//! Return the LDS for this thread
|
||||
address localDataStorage() const { return localDataStorage_; }
|
||||
//! Return the size of the local memory for this thread.
|
||||
size_t localDataSize() const { return localDataSize_; }
|
||||
|
||||
address baseWorkItemsStack() { return baseWorkItemsStack_; }
|
||||
|
||||
Operation* operation() { return reinterpret_cast<Operation*>(operation_); }
|
||||
bool isOperationValid() { return waitingOp_ > 0; }
|
||||
|
||||
//! Enqueue a new operation to execute in this thread.
|
||||
void enqueue(Operation& op);
|
||||
//! Signal to start processing the commands in the queue.
|
||||
void flush() { amd::ScopedLock sl(queueLock_); queueLock_.notify(); }
|
||||
|
||||
//! This thread's execution engine.
|
||||
void run(void* data) {
|
||||
loop();
|
||||
}
|
||||
|
||||
//! Return the currently executing WorkerThread's instance.
|
||||
static WorkerThread* current()
|
||||
{
|
||||
return static_cast<WorkerThread*>(Thread::current());
|
||||
}
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
extern "C" intptr_t _StackContext_setjmp(intptr_t* regs);
|
||||
|
||||
#if !defined(ATI_ARCH_ARM)
|
||||
ALWAYSINLINE
|
||||
#endif
|
||||
intptr_t
|
||||
StackContext::setjmp()
|
||||
{
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
return ::setjmp(env_);
|
||||
#else
|
||||
return _StackContext_setjmp(regs_);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" void _StackContext_longjmp(const intptr_t* env, intptr_t val);
|
||||
|
||||
ALWAYSINLINE void
|
||||
StackContext::longjmp(intptr_t val) const
|
||||
{
|
||||
#if defined(ATI_ARCH_ARM)
|
||||
return ::longjmp(*const_cast<jmp_buf*>(&env_), val);
|
||||
#else
|
||||
return _StackContext_longjmp(regs_, val);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" void _WorkGroup_callKernel(
|
||||
address params,
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr);
|
||||
|
||||
extern "C" void _WorkGroup_callKernelProtectedReturn(
|
||||
address params,
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr);
|
||||
|
||||
|
||||
ALWAYSINLINE void
|
||||
WorkGroup::callKernel(
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr)
|
||||
{
|
||||
_WorkGroup_callKernel(params_, entryPoint, stackPtr);
|
||||
}
|
||||
|
||||
// This version support the case of changing the stack for fibers.
|
||||
ALWAYSINLINE void
|
||||
WorkGroup::callKernelProtectedReturn(
|
||||
kernelentrypoint_t entryPoint,
|
||||
address stackPtr)
|
||||
{
|
||||
_WorkGroup_callKernelProtectedReturn(params_, entryPoint, stackPtr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif /*OPERATION_HPP_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUDEVICE_HPP_
|
||||
#define CPUDEVICE_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/cpu/cpuvirtual.hpp"
|
||||
#include "device/cpu/cpusettings.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
#if defined(__linux__) && defined(NUMA_SUPPORT)
|
||||
#include <numa.h>
|
||||
#endif
|
||||
|
||||
#include "acl.h"
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
//! Maximum number of the supported samplers
|
||||
const static uint32_t MaxSamplers = 16;
|
||||
//! Maximum number of supported read images
|
||||
const static uint32_t MaxReadImage = 128;
|
||||
//! Maximum number of supported write images
|
||||
const static uint32_t MaxWriteImage = 64;
|
||||
//! Maximum number of supported read/write images
|
||||
const static uint32_t MaxReadWriteImage = 64;
|
||||
|
||||
/*! \addtogroup CPU CPU Device Implementation
|
||||
* @{
|
||||
*
|
||||
* \addtogroup CPUDevice Device
|
||||
*
|
||||
* \copydoc cpu::Device
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! A CPU device ordinal
|
||||
class Device : public amd::Device
|
||||
{
|
||||
protected:
|
||||
static aclCompiler* compiler_;
|
||||
public:
|
||||
aclCompiler* compiler() const { return compiler_; }
|
||||
|
||||
public:
|
||||
static bool init(void);
|
||||
|
||||
//! Shutdown CPU device
|
||||
static void tearDown();
|
||||
|
||||
//! Construct a new identifier
|
||||
Device(Device* parent = NULL) :
|
||||
amd::Device(parent),
|
||||
workerThreadsAffinity_(NULL)
|
||||
{}
|
||||
|
||||
virtual ~Device();
|
||||
|
||||
bool create();
|
||||
|
||||
virtual cl_int createSubDevices(
|
||||
device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices);
|
||||
|
||||
//! Instantiate a new virtual device
|
||||
virtual device::VirtualDevice* createVirtualDevice(
|
||||
bool profiling,
|
||||
bool interopQueue
|
||||
#if cl_amd_open_video
|
||||
, void* calVideoProperties = NULL
|
||||
#endif // cl_amd_open_video
|
||||
, uint deviceQueueSize = 0
|
||||
)
|
||||
{
|
||||
VirtualCPU* virtualCpu = new VirtualCPU(*this);
|
||||
if (virtualCpu != NULL && !virtualCpu->acceptingCommands()) {
|
||||
virtualCpu->terminate();
|
||||
delete virtualCpu;
|
||||
virtualCpu = NULL;
|
||||
}
|
||||
return virtualCpu;
|
||||
}
|
||||
|
||||
//! Compile the given source code.
|
||||
virtual device::Program* createProgram(int oclVer = 120);
|
||||
|
||||
//! Just returns NULL as CPU devices use the host memory
|
||||
virtual device::Memory* createMemory(amd::Memory& owner) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Sampler object allocation
|
||||
virtual bool createSampler(
|
||||
const amd::Sampler& owner, //!< abstraction layer sampler object
|
||||
device::Sampler** sampler //!< device sampler object
|
||||
) const
|
||||
{
|
||||
// Just return NULL on CPU device
|
||||
*sampler = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Reallocates device memory obje
|
||||
virtual bool reallocMemory(amd::Memory& owner) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Just returns NULL as CPU devices use the host memory
|
||||
virtual device::Memory* createView(
|
||||
amd::Memory& owner, //!< Owner memory object
|
||||
const device::Memory& parent //!< Parent device memory object for the view
|
||||
) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! Acquire external graphics API object in the host thread
|
||||
//! Needed for OpenGL objects on CPU device
|
||||
|
||||
//! Return true if initialized interoperability, otherwise false
|
||||
virtual bool bindExternalDevice(intptr_t type, void* pDevice, void* pContext, bool validateOnly)
|
||||
{
|
||||
return true; // On CPU always avail if pD3DDevice is not NULL
|
||||
}
|
||||
|
||||
virtual bool unbindExternalDevice(intptr_t type, void* pDevice, void* pContext, bool validateOnly)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Gets a pointer to a region of host-visible memory for use as the target
|
||||
//! of a non-blocking map for a given memory object
|
||||
virtual void* allocMapTarget(
|
||||
amd::Memory& mem, //!< Abstraction layer memory object
|
||||
const amd::Coord3D& origin, //!< The map location in memory
|
||||
const amd::Coord3D& region, //!< The map region in memory
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the mapped memory
|
||||
size_t* slicePitch = NULL //!< Slice for the mapped memory
|
||||
);
|
||||
|
||||
//! Releases non-blocking map target memory
|
||||
virtual void freeMapTarget(amd::Memory& mem, void* target);
|
||||
|
||||
//! Empty implementation on a CPU device
|
||||
virtual bool globalFreeMemory(size_t* freeMemory) const { return false; }
|
||||
|
||||
//! Get CPU device settings
|
||||
const cpu::Settings& settings() const
|
||||
{ return reinterpret_cast<cpu::Settings&>(*settings_); }
|
||||
|
||||
bool hasAVXInstructions() const
|
||||
{ return (settings().cpuFeatures_ & Settings::AVXInstructions) ? true : false; }
|
||||
|
||||
bool hasFMA4Instructions() const
|
||||
{ return (settings().cpuFeatures_ & Settings::FMA4Instructions) ? true : false; }
|
||||
|
||||
static size_t getMaxWorkerThreadsNumber() { return maxWorkerThreads_; }
|
||||
|
||||
void setWorkerThreadsAffinity(
|
||||
cl_uint numWorkerThreads,
|
||||
const amd::Os::ThreadAffinityMask* threadsAffinityMask,
|
||||
uint& baseCoreId);
|
||||
|
||||
const amd::Os::ThreadAffinityMask* getWorkerThreadsAffinity() const
|
||||
{
|
||||
return workerThreadsAffinity_;
|
||||
}
|
||||
//! host memory alloc
|
||||
virtual void* svmAlloc(amd::Context& context, size_t size, size_t alignment, cl_svm_mem_flags flags) const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//! host memory deallocation
|
||||
virtual void svmFree(void* ptr) const
|
||||
{
|
||||
return;
|
||||
}
|
||||
private:
|
||||
bool initSubDevice(
|
||||
device::Info& info,
|
||||
cl_uint maxComputeUnits,
|
||||
const device::CreateSubDevicesInfo& create_info);
|
||||
|
||||
cl_int partitionEqually(
|
||||
const device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices);
|
||||
|
||||
cl_int partitionByCounts(
|
||||
const device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices);
|
||||
|
||||
cl_int partitionByAffinityDomainNUMA(
|
||||
const device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices);
|
||||
|
||||
cl_int partitionByAffinityDomainCacheLevel(
|
||||
const device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices);
|
||||
|
||||
private:
|
||||
#if defined(__linux__) && defined(NUMA_SUPPORT)
|
||||
public:
|
||||
const nodemask_t* getNumaMask() const
|
||||
{
|
||||
return (info_.partitionCreateInfo_.type_ == device::PartitionType::BY_AFFINITY_DOMAIN &&
|
||||
info_.partitionCreateInfo_.byAffinityDomain_.numa_) ?
|
||||
numaMask_ : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
nodemask_t* numaMask_;
|
||||
amd::Os::ThreadAffinityMask* workerThreadsAffinity_; //!< As the number of compute units.
|
||||
};
|
||||
#else
|
||||
amd::Os::ThreadAffinityMask* workerThreadsAffinity_; //!< As the number of compute units.
|
||||
#endif
|
||||
|
||||
static size_t maxWorkerThreads_; //!< Maximum number of Worker Threads
|
||||
};
|
||||
|
||||
/*! @}
|
||||
* @}
|
||||
*/
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUDEVICE_HPP_
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Copyright 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUFEAT_HPP
|
||||
#define CPUFEAT_HPP
|
||||
|
||||
#define CPUFEAT_CX_SSE3 (1 << 0)
|
||||
#define CPUFEAT_CX_SSSE3 (1 << 9)
|
||||
#define CPUFEAT_CX_CMPXCHG16B (1 << 13)
|
||||
#define CPUFEAT_CX_SSE4_1 (1 << 19)
|
||||
#define CPUFEAT_CX_SSE4_2 (1 << 20)
|
||||
#define CPUFEAT_CX_POPCNT (1 << 23)
|
||||
#define CPUFEAT_CX_AES (1 << 25)
|
||||
#define CPUFEAT_CX_OSXSAVE (1 << 27)
|
||||
#define CPUFEAT_CX_AVX (1 << 28)
|
||||
|
||||
#define INTEL_CPUFEAT_CX_FMA3 (1 << 12)
|
||||
|
||||
#define AMD_CPUFEAT_CX_FMA4 (1 << 16)
|
||||
#define AMD_CPUFEAT_CX_XOP (1 << 11)
|
||||
#define AMD_CPUFEAT_CX_SSE4A (1 << 6)
|
||||
|
||||
#define CPUFEAT_DX_SSE (1 < 25)
|
||||
#define CPUFEAT_DX_SSE2 (1 << 26)
|
||||
|
||||
#endif // CPUFEAT_HPP
|
||||
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
#
|
||||
|
||||
.text
|
||||
.globl _WorkGroup_callKernel
|
||||
#if defined(ATI_ARCH_X86)
|
||||
.type _WorkGroup_callKernel, @function
|
||||
_WorkGroup_callKernel:
|
||||
#if defined(_LP64)
|
||||
pushq %rbp
|
||||
movq %rsp, %rbp
|
||||
movq %rdx, %rsp // stackPtr
|
||||
call *%rsi
|
||||
movq %rbp, %rsp
|
||||
popq %rbp
|
||||
#else // _LP64
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
movl 0x10(%ebp), %esp // stackPtr
|
||||
movl 0x0C(%ebp), %edx // entryPoint
|
||||
movl 0x08(%ebp), %ecx // params
|
||||
movl %ecx, (%esp)
|
||||
call *%edx
|
||||
movl %ebp, %esp
|
||||
popl %ebp
|
||||
#endif // _LP64
|
||||
ret
|
||||
#elif defined(ATI_ARCH_ARM)
|
||||
.type _WorkGroup_callKernel, %function
|
||||
_WorkGroup_callKernel:
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
.globl _WorkGroup_callKernelProtectedReturn
|
||||
#if defined(ATI_ARCH_X86)
|
||||
.type _WorkGroup_callKernelProtectedReturn, @function
|
||||
_WorkGroup_callKernelProtectedReturn:
|
||||
#if defined(_LP64)
|
||||
movq %rbp, %rax
|
||||
movq %rsp, %rbp
|
||||
movq %rdx, %rsp // stackPtr
|
||||
subq $CPUKERNEL_STACK_ALIGN, %rsp
|
||||
movq %rax, 0x08(%rsp) // save rbp
|
||||
movq %rbx, 0x00(%rsp) // save rbx
|
||||
movq (%rbp), %rbx // return address
|
||||
|
||||
call *%rsi
|
||||
|
||||
movq %rbx, %rdx
|
||||
movq %rbp, %rcx
|
||||
movq 0x00(%rsp), %rbx // load rbx
|
||||
movq 0x08(%rsp), %rbp // load rbp
|
||||
movq %rcx, %rsp
|
||||
addq $0x08, %rsp // skip return address
|
||||
jmp *%rdx
|
||||
#else // !_LP64
|
||||
movl %ebp, %eax
|
||||
movl %esp, %ebp
|
||||
movl 0x0C(%ebp), %esp // stackPtr
|
||||
subl $CPUKERNEL_STACK_ALIGN, %esp
|
||||
movl 0x04(%ebp), %ecx // params
|
||||
movl %eax, 0x08(%esp) // save ebp
|
||||
movl %ebx, 0x04(%esp) // save ebx
|
||||
movl %ecx, 0x00(%esp) // pass params
|
||||
movl 0x00(%ebp), %ebx // return address
|
||||
movl 0x08(%ebp), %edx // entryPoint
|
||||
|
||||
call *%edx
|
||||
|
||||
movl %ebx, %edx
|
||||
movl %ebp, %ecx
|
||||
movl 0x04(%esp), %ebx // load ebx
|
||||
movl 0x08(%esp), %ebp // load ebp
|
||||
movl %ecx, %esp
|
||||
addl $0x4, %esp // skip return address
|
||||
jmp *%edx
|
||||
#endif // !_LP64
|
||||
#elif defined(ATI_ARCH_ARM)
|
||||
.type _WorkGroup_callKernelProtectedReturn, %function
|
||||
_WorkGroup_callKernelProtectedReturn:
|
||||
bx lr
|
||||
#endif
|
||||
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
;
|
||||
; Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
;
|
||||
|
||||
ifndef _WIN64
|
||||
.386
|
||||
.model flat, c
|
||||
endif ; !_WIN64
|
||||
|
||||
OPTION PROLOGUE:NONE
|
||||
OPTION EPILOGUE:NONE
|
||||
.code
|
||||
|
||||
ifndef _WIN64
|
||||
|
||||
_WorkGroup_callKernel proc
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
mov esp, 10h[ebp] ; stackPtr
|
||||
mov edx, 0Ch[ebp] ; entryPoint
|
||||
push 08h[ebp] ; params
|
||||
call edx
|
||||
mov esp, ebp
|
||||
pop ebp
|
||||
ret
|
||||
_WorkGroup_callKernel endp
|
||||
|
||||
_WorkGroup_callKernelProtectedReturn proc
|
||||
mov eax, ebp
|
||||
mov ebp, esp
|
||||
mov esp, 0Ch[ebp] ; stackPtr
|
||||
sub esp, CPUKERNEL_STACK_ALIGN
|
||||
mov 04h[esp], eax ; save ebp
|
||||
mov 00h[esp], ebx ; save ebx
|
||||
mov ebx, 00h[ebp] ; return address
|
||||
mov edx, 08h[ebp] ; entryPoint
|
||||
|
||||
push 04h[ebp] ; params
|
||||
call edx
|
||||
|
||||
mov edx, ebx
|
||||
mov ecx, ebp
|
||||
mov ebx, 04h[esp] ; load ebx
|
||||
mov ebp, 08h[esp] ; load ebp
|
||||
mov esp, ecx
|
||||
add esp, 04h ; skip return address
|
||||
jmp edx
|
||||
_WorkGroup_callKernelProtectedReturn endp
|
||||
|
||||
else ; _WIN64
|
||||
|
||||
_WorkGroup_callKernel proc
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
mov rsp, r8 ; stackPtr
|
||||
call rdx
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
ret
|
||||
_WorkGroup_callKernel endp
|
||||
|
||||
_WorkGroup_callKernelProtectedReturn proc
|
||||
mov rax, rbp
|
||||
mov rbp, rsp
|
||||
mov rsp, r8 ; stackPtr
|
||||
sub rsp, CPUKERNEL_STACK_ALIGN
|
||||
mov 08h[rsp], rax ; save rbp
|
||||
mov 00h[rsp], rbx ; save rbx
|
||||
mov rbx, [rbp] ; return address
|
||||
|
||||
call rdx
|
||||
|
||||
mov rdx, rbx
|
||||
mov rcx, rbp
|
||||
mov rbx, 00h[rsp] ; load rbx
|
||||
mov rbp, 08h[rsp] ; load rbp
|
||||
mov rsp, rcx
|
||||
add rsp, 08h ; skip return address
|
||||
jmp rdx
|
||||
_WorkGroup_callKernelProtectedReturn endp
|
||||
|
||||
endif ; _WIN64
|
||||
|
||||
end
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUKERNEL_HPP_
|
||||
#define CPUKERNEL_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include <amdocl/cl_kernel.h>
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
//! \class CPU kernel
|
||||
class Kernel : public device::Kernel
|
||||
{
|
||||
private:
|
||||
const void* entryPoint_; //!< entry for the kernel
|
||||
|
||||
std::vector< std::pair<size_t, size_t> > args_;
|
||||
public:
|
||||
uint nature_; //!< kernel's nature
|
||||
uint privateSize_; //!< WorkItem's private memory size (in bytes)
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
Kernel(const Kernel&);
|
||||
//! Disable operator=
|
||||
Kernel& operator=(const Kernel&);
|
||||
|
||||
public:
|
||||
void addArg(size_t size, size_t alignment) {
|
||||
args_.push_back(std::pair<size_t, size_t>(size, alignment));
|
||||
}
|
||||
|
||||
size_t getArgSize(int argIndex) const {
|
||||
return args_[argIndex].first;
|
||||
}
|
||||
|
||||
size_t getArgAlignment(int argIndex) const {
|
||||
return args_[argIndex].second;
|
||||
}
|
||||
|
||||
//! Default constructor
|
||||
Kernel(const std::string& name)
|
||||
: device::Kernel(name), entryPoint_(NULL), nature_(0),
|
||||
privateSize_(CLK_PRIVATE_MEMORY_SIZE)
|
||||
{
|
||||
workGroupInfo_.size_ = CPU_MAX_WORKGROUP_SIZE;
|
||||
}
|
||||
|
||||
//! Default destructor
|
||||
~Kernel() {}
|
||||
|
||||
//! Returns the CPU kernel entry point
|
||||
const void* getEntryPoint() const { return entryPoint_; }
|
||||
|
||||
//! Sets the CPU kernel entry point
|
||||
void setEntryPoint(const void* entryPoint) { entryPoint_ = entryPoint; }
|
||||
|
||||
//! Returns true if the kernel has a call to barrier
|
||||
bool hasBarrier() const { return 0 != (nature_ & KN_HAS_BARRIER); }
|
||||
|
||||
//! Returns the private memory size of a single WorkItem
|
||||
uint getWorkItemPrivateMemSize() const { return privateSize_; }
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUKERNEL_HPP_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUPROGRAM_HPP_
|
||||
#define CPUPROGRAM_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/cpu/cpubinary.hpp"
|
||||
#include <string>
|
||||
|
||||
#include "jit.h"
|
||||
|
||||
// forward declaration
|
||||
namespace amd {
|
||||
namespace option {
|
||||
class Options;
|
||||
} // option
|
||||
} // amd
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
//! \class CPU program
|
||||
class Program : public device::Program
|
||||
{
|
||||
private:
|
||||
aclJITObjectImage JITBinary;
|
||||
std::string sourceFileName_; //!< The source image.
|
||||
void* handle_; // @todo: remove me
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
Program(Device& cpuDev)
|
||||
: device::Program(cpuDev), JITBinary(NULL), handle_(NULL) {}
|
||||
|
||||
//! Default destructor
|
||||
~Program();
|
||||
|
||||
//! pre-compile setup for CPU
|
||||
virtual bool initBuild(amd::option::Options* options);
|
||||
|
||||
//! post-compile setup for CPU
|
||||
virtual bool finiBuild(bool isBuildGood);
|
||||
|
||||
//! Compiles CPU program
|
||||
virtual bool compileImpl(
|
||||
const std::string& sourceCode,
|
||||
const std::vector<const std::string*>& headers,
|
||||
const char** headerIncludeNames,
|
||||
amd::option::Options* options );
|
||||
|
||||
//! Links CPU program
|
||||
virtual bool linkImpl(amd::option::Options* options = NULL);
|
||||
|
||||
//! Links CPU programs
|
||||
virtual bool linkImpl(
|
||||
const std::vector<device::Program*>& inputPrograms,
|
||||
amd::option::Options* options = NULL,
|
||||
bool createLibrary = false);
|
||||
|
||||
virtual bool createBinary(amd::option::Options* options);
|
||||
|
||||
//! Returns the device object, associated with this program.
|
||||
const Device& device() {
|
||||
return static_cast<const Device&>(device::Program::device());
|
||||
}
|
||||
|
||||
/*! \brief Invokes the LLC compiler for the LLVM binary compilation
|
||||
* to x86 ASM text source code and ISA binary
|
||||
*
|
||||
* \return True if we successefully compiled a CPU program
|
||||
*/
|
||||
bool compileBinaryToISA(
|
||||
amd::option::Options* options //!< options for compilation
|
||||
);
|
||||
|
||||
//! Load the library into memory
|
||||
bool loadDllCode(amd::option::Options* options, bool addElfSymbols=false);
|
||||
|
||||
//! Initialize binary for CPU
|
||||
virtual bool initClBinary();
|
||||
|
||||
//! Release binary for CPU
|
||||
virtual void releaseClBinary();
|
||||
|
||||
ClBinary* clBinary() {
|
||||
return static_cast<ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
const ClBinary* clBinary() const {
|
||||
return static_cast<const ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
|
||||
aclJITObjectImage getJITBinary() { return this->JITBinary; }
|
||||
void setJITBinary(aclJITObjectImage JITBinary) { this->JITBinary = JITBinary; }
|
||||
|
||||
private:
|
||||
aclCompiler* compiler() { return static_cast<const Device&>(device()).compiler(); }
|
||||
|
||||
//! Disable default copy constructor
|
||||
Program(const Program&);
|
||||
|
||||
//! Disable operator=
|
||||
Program& operator=(const Program&);
|
||||
|
||||
std::string dllFileName_; //!< File name of the dll with kernels
|
||||
protected:
|
||||
virtual bool isElf(const char* bin) const {
|
||||
return amd::isElfHeader(bin, LP64_SWITCH(ELFCLASS32, ELFCLASS64));
|
||||
}
|
||||
|
||||
virtual const aclTargetInfo & info(const char * str = "");
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUPROGRAM_HPP_
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Copyright 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/cpu/cpusettings.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
namespace cpu {
|
||||
|
||||
bool
|
||||
Settings::create()
|
||||
{
|
||||
largeHostMemAlloc_ = true;
|
||||
|
||||
// This code is temporary until cl_khr_fp64 is unconditional
|
||||
if (flagIsDefault(CL_KHR_FP64) || CL_KHR_FP64) {
|
||||
enableExtension(ClKhrFp64);
|
||||
}
|
||||
|
||||
enableExtension(ClAmdFp64);
|
||||
enableExtension(ClKhrGlobalInt32BaseAtomics);
|
||||
enableExtension(ClKhrGlobalInt32ExtendedAtomics);
|
||||
enableExtension(ClKhrLocalInt32BaseAtomics);
|
||||
enableExtension(ClKhrLocalInt32ExtendedAtomics);
|
||||
|
||||
#ifdef _LP64
|
||||
enableExtension(ClKhrInt64BaseAtomics);
|
||||
enableExtension(ClKhrInt64ExtendedAtomics);
|
||||
#endif // _LP64
|
||||
enableExtension(ClKhrByteAddressableStore);
|
||||
enableExtension(ClKhrGlSharing);
|
||||
enableExtension(ClKhrGlEvent);
|
||||
enableExtension(ClExtDeviceFission);
|
||||
enableExtension(ClAmdDeviceAttributeQuery);
|
||||
enableExtension(ClAmdVec3);
|
||||
enableExtension(ClAmdMediaOps);
|
||||
enableExtension(ClAmdMediaOps2);
|
||||
enableExtension(ClAmdPopcnt);
|
||||
enableExtension(ClAmdPrintf);
|
||||
|
||||
// enableExtension(ClKhrSelectFpRoundingMode);
|
||||
enableExtension(ClKhr3DImageWrites);
|
||||
|
||||
// enableExtension(ClKhrFp16);
|
||||
|
||||
#if defined(_WIN32)
|
||||
enableExtension(ClKhrD3d10Sharing);
|
||||
#endif // _WIN32
|
||||
enableExtension(ClKhrSpir);
|
||||
|
||||
// Enable some OpenCL 2.0 extensions
|
||||
if (OPENCL_MAJOR >= 2) {
|
||||
partialDispatch_ = true;
|
||||
enableExtension(ClKhrSubGroups);
|
||||
supportDepthsRGB_ = true;
|
||||
}
|
||||
|
||||
// Map CPUID feature bits to our own feature bits
|
||||
const int sse2_features = CPUFEAT_DX_SSE | CPUFEAT_DX_SSE2;
|
||||
const int avx_features = CPUFEAT_CX_SSE3 | CPUFEAT_CX_SSSE3 |
|
||||
CPUFEAT_CX_SSE4_1 | CPUFEAT_CX_SSE4_2 |
|
||||
CPUFEAT_CX_POPCNT | CPUFEAT_CX_AVX |
|
||||
CPUFEAT_CX_OSXSAVE;
|
||||
const int fma3_features = INTEL_CPUFEAT_CX_FMA3;
|
||||
const int fma4_features = AMD_CPUFEAT_CX_FMA4 | AMD_CPUFEAT_CX_XOP;
|
||||
int regs[4];
|
||||
|
||||
#if defined(ATI_ARCH_X86)
|
||||
amd::Os::cpuid(regs, 0x0);
|
||||
bool isAmd = regs[1] == ('A' | ('u' << 8) | ('t' << 16) | ('h' << 24));
|
||||
bool isIntel = regs[1] == ('G' | ('e' << 8) | ('n' << 16) | ('u' << 24));
|
||||
|
||||
amd::Os::cpuid(regs, 0x1);
|
||||
|
||||
cpuFeatures_ = (regs[3] & sse2_features) == sse2_features ?
|
||||
SSE2Instructions : 0;
|
||||
|
||||
if ((regs[2] & avx_features) == avx_features) {
|
||||
// Check for state support
|
||||
uint64_t xcr0 = amd::Os::xgetbv(0);
|
||||
|
||||
// Check for SSE and YMM bits (1 and 2)
|
||||
if (((uint32_t)xcr0 & 0x6U) == 0x6U) {
|
||||
cpuFeatures_ |= AVXInstructions;
|
||||
|
||||
// Now check for FMA and XOP
|
||||
if (isIntel) {
|
||||
cpuFeatures_ |= (regs[2] & fma3_features) == fma3_features ?
|
||||
FMA3Instructions : 0;
|
||||
}
|
||||
|
||||
if (isAmd) {
|
||||
amd::Os::cpuid(regs, 0x80000001);
|
||||
cpuFeatures_ |= (regs[2] & fma4_features) == fma4_features ?
|
||||
FMA4Instructions : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // ATI_ARCH_X86
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUSETTINGS_HPP_
|
||||
#define CPUSETTINGS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/cpu/cpufeat.hpp"
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
//! Device settings
|
||||
class Settings : public device::Settings
|
||||
{
|
||||
public:
|
||||
enum CpuFeatures {
|
||||
SSE2Instructions = 0x01,
|
||||
AVXInstructions = 0x02, // Processor reports SSSE3, SSE4_1, SSE4_2
|
||||
// POPCNT and AVX
|
||||
FMA3Instructions = 0x04, // Intel processor reports FMA3
|
||||
FMA4Instructions = 0x08 // AMD processor reports FMA4 and XOP
|
||||
};
|
||||
uint32_t cpuFeatures_; //!< CPU features
|
||||
|
||||
//! Default constructor
|
||||
Settings() { cpuFeatures_ = 0; }
|
||||
|
||||
//! Creates settings
|
||||
bool create();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Settings(const Settings&);
|
||||
|
||||
//! Disable assignment
|
||||
Settings& operator=(const Settings&);
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUSETTINGS_HPP_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,627 @@
|
||||
//
|
||||
// Copyright 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/cpu/cpuvirtual.hpp"
|
||||
#include "device/cpu/cpudevice.hpp"
|
||||
#include "device/cpu/cpucommand.hpp"
|
||||
#include "device/blit.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/commandqueue.hpp"
|
||||
#include "platform/memory.hpp"
|
||||
#include "platform/sampler.hpp"
|
||||
#include "os/os.hpp"
|
||||
|
||||
namespace cpu {
|
||||
|
||||
amd::Atomic<size_t> VirtualCPU::numWorkerThreads_(0);
|
||||
|
||||
VirtualCPU::VirtualCPU(Device& device)
|
||||
: device::VirtualDevice(device), acceptingCommands_(false)
|
||||
{
|
||||
const size_t numCores = device.info().maxComputeUnits_;
|
||||
|
||||
if ((numWorkerThreads_ += numCores) >= Device::getMaxWorkerThreadsNumber()) {
|
||||
numWorkerThreads_ -= numCores;
|
||||
cores_ = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
cores_ = new(std::nothrow) WorkerThread*[numCores];
|
||||
if (cores_ == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear memory for the worker threads
|
||||
memset(cores_, 0, numCores * sizeof(WorkerThread*));
|
||||
|
||||
#if defined(__linux__)
|
||||
const bool isNuma =
|
||||
#if defined(NUMA_SUPPORT)
|
||||
device.getNumaMask() == NULL;
|
||||
#else
|
||||
false;
|
||||
#endif // NUMA_SUPPORT
|
||||
const amd::Os::ThreadAffinityMask* affinityMask = isNuma ? NULL :
|
||||
#else
|
||||
const amd::Os::ThreadAffinityMask* affinityMask =
|
||||
#endif
|
||||
device.getWorkerThreadsAffinity();
|
||||
|
||||
uint coreId = affinityMask != NULL ? affinityMask->getFirstSet() : (uint)-1;
|
||||
|
||||
for (size_t i = 0; i < numCores; ++i) {
|
||||
WorkerThread* thread = cores_[i] = new WorkerThread(device);
|
||||
if (thread == NULL) {
|
||||
for (size_t j = 0; j < i; ++j) {
|
||||
cores_[j]->resume();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread->state() != amd::Thread::INITIALIZED) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
if (!isNuma) {
|
||||
if (coreId == (uint)-1) {
|
||||
thread->setAffinity((uint) i);
|
||||
}
|
||||
else {
|
||||
thread->setAffinity(coreId);
|
||||
coreId = affinityMask->getNextSet(coreId);
|
||||
}
|
||||
}
|
||||
#else // On Windows we set an affinity mask and not a specific ID.
|
||||
if (coreId != (uint)-1) {
|
||||
thread->setAffinity(*affinityMask);
|
||||
}
|
||||
#endif
|
||||
thread->start();
|
||||
}
|
||||
|
||||
blitMgr_ = new device::HostBlitManager(*this);
|
||||
if ((NULL == blitMgr_) || !blitMgr_->create(device)) {
|
||||
LogError("Could not create BlitManager!");
|
||||
return;
|
||||
}
|
||||
|
||||
acceptingCommands_ = true;
|
||||
}
|
||||
|
||||
VirtualCPU::~VirtualCPU()
|
||||
{
|
||||
if (cores_ == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete blitMgr_;
|
||||
|
||||
const size_t numCores = device().info().maxComputeUnits_;
|
||||
for (size_t i = 0; i < numCores; ++i) {
|
||||
delete cores_[i];
|
||||
}
|
||||
numWorkerThreads_ -= numCores;
|
||||
delete[] cores_;
|
||||
}
|
||||
|
||||
bool
|
||||
VirtualCPU::terminate()
|
||||
{
|
||||
if (cores_ == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t numCores = device().info().maxComputeUnits_;
|
||||
for (size_t i = 0; i < numCores; ++i) {
|
||||
if (cores_[i]) {
|
||||
cores_[i]->terminate();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitReadMemory(amd::ReadMemoryCommand& vcmd)
|
||||
{
|
||||
vcmd.setStatus(CL_RUNNING);
|
||||
|
||||
bool result = false;
|
||||
device::Memory memory(vcmd.source());
|
||||
|
||||
// Ensure memory up-to-date
|
||||
vcmd.source().cacheWriteBack();
|
||||
|
||||
switch (vcmd.type()) {
|
||||
case CL_COMMAND_READ_BUFFER:
|
||||
result = blitMgr().readBuffer(memory, vcmd.destination(),
|
||||
vcmd.origin(), vcmd.size(), vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_READ_BUFFER_RECT:
|
||||
result = blitMgr().readBufferRect(memory,
|
||||
vcmd.destination(), vcmd.bufRect(), vcmd.hostRect(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_READ_IMAGE:
|
||||
result = blitMgr().readImage(memory, vcmd.destination(),
|
||||
vcmd.origin(), vcmd.size(), vcmd.rowPitch(), vcmd.slicePitch(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
default:
|
||||
LogError("Unsupported type for the read command");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
LogError("submitReadMemory failed!");
|
||||
vcmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
vcmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitWriteMemory(amd::WriteMemoryCommand& vcmd)
|
||||
{
|
||||
vcmd.setStatus(CL_RUNNING);
|
||||
|
||||
bool result = false;
|
||||
device::Memory memory(vcmd.destination());
|
||||
|
||||
// Ensure memory up-to-date
|
||||
vcmd.destination().cacheWriteBack();
|
||||
|
||||
// Process different write commands
|
||||
switch (vcmd.type()) {
|
||||
case CL_COMMAND_WRITE_BUFFER:
|
||||
result = blitMgr().writeBuffer(vcmd.source(), memory,
|
||||
vcmd.origin(), vcmd.size(), vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_WRITE_BUFFER_RECT:
|
||||
result = blitMgr().writeBufferRect(vcmd.source(), memory,
|
||||
vcmd.hostRect(), vcmd.bufRect(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_WRITE_IMAGE:
|
||||
result = blitMgr().writeImage(vcmd.source(), memory,
|
||||
vcmd.origin(), vcmd.size(), vcmd.rowPitch(), vcmd.slicePitch(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
default:
|
||||
LogError("Unsupported type for the write command");
|
||||
break;
|
||||
}
|
||||
|
||||
// Mark cache as clean (CPU works directly on backing store)
|
||||
vcmd.destination().signalWrite(NULL);
|
||||
|
||||
if (!result) {
|
||||
LogError("submitWriteMemory failed!");
|
||||
vcmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
vcmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VirtualCPU::submitCopyMemory(amd::CopyMemoryCommand& vcmd)
|
||||
{
|
||||
vcmd.setStatus(CL_RUNNING);
|
||||
|
||||
// Ensure memory up-to-date
|
||||
vcmd.source().cacheWriteBack();
|
||||
vcmd.destination().cacheWriteBack();
|
||||
|
||||
// Translate memory references and ensure cache up-to-date
|
||||
device::Memory dstMemory(vcmd.destination());
|
||||
device::Memory srcMemory(vcmd.source());
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Check if HW can be used for memory copy
|
||||
switch (vcmd.type()) {
|
||||
case CL_COMMAND_COPY_BUFFER:
|
||||
result = blitMgr().copyBuffer(srcMemory, dstMemory,
|
||||
vcmd.srcOrigin(), vcmd.dstOrigin(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_COPY_BUFFER_RECT:
|
||||
result = blitMgr().copyBufferRect(srcMemory, dstMemory,
|
||||
vcmd.srcRect(), vcmd.dstRect(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_COPY_IMAGE_TO_BUFFER:
|
||||
result = blitMgr().copyImageToBuffer(srcMemory, dstMemory,
|
||||
vcmd.srcOrigin(), vcmd.dstOrigin(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_COPY_BUFFER_TO_IMAGE:
|
||||
result = blitMgr().copyBufferToImage(srcMemory, dstMemory,
|
||||
vcmd.srcOrigin(), vcmd.dstOrigin(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_COPY_IMAGE:
|
||||
result = blitMgr().copyImage(srcMemory, dstMemory,
|
||||
vcmd.srcOrigin(), vcmd.dstOrigin(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
default:
|
||||
LogError("Unsupported command type for memory copy!");
|
||||
break;
|
||||
}
|
||||
|
||||
// Mark cache as clean (CPU works directly on backing store)
|
||||
vcmd.destination().signalWrite(NULL);
|
||||
|
||||
if (!result) {
|
||||
LogError("submitCopyMemory failed!");
|
||||
vcmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
vcmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitMapMemory(amd::MapMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
|
||||
if (cmd.mapFlags() & CL_MAP_READ
|
||||
|| cmd.mapFlags() & CL_MAP_WRITE) {
|
||||
LogInfo("cpu::VirtualCPU::submitMapMemory() CL_MAP_READ and CL_MAP_WRITE ignored");
|
||||
}
|
||||
|
||||
// Ensure memory up-to-date
|
||||
cmd.memory().cacheWriteBack();
|
||||
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitUnmapMemory(amd::UnmapMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
|
||||
// Mark cache as clean (CPU works directly on backing store)
|
||||
cmd.memory().signalWrite(NULL);
|
||||
|
||||
//! @todo:dgladdin: strictly speaking we should check that the mem object was mapped
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitFillMemory(amd::FillMemoryCommand& vcmd)
|
||||
{
|
||||
vcmd.setStatus(CL_RUNNING);
|
||||
|
||||
device::Memory memory(vcmd.memory());
|
||||
|
||||
vcmd.memory().cacheWriteBack();
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Find the the right fill operation
|
||||
switch (vcmd.type()) {
|
||||
case CL_COMMAND_FILL_BUFFER:
|
||||
result = blitMgr().fillBuffer(memory, vcmd.pattern(),
|
||||
vcmd.patternSize(), vcmd.origin(), vcmd.size(),
|
||||
vcmd.isEntireMemory());
|
||||
break;
|
||||
case CL_COMMAND_FILL_IMAGE:
|
||||
result = blitMgr().fillImage(memory, vcmd.pattern(),
|
||||
vcmd.origin(), vcmd.size(), vcmd.isEntireMemory());
|
||||
break;
|
||||
default:
|
||||
LogError("Unsupported command type for FillMemory!");
|
||||
break;
|
||||
}
|
||||
|
||||
vcmd.memory().signalWrite(NULL);
|
||||
|
||||
if (!result) {
|
||||
LogError("submitFillMemory failed!");
|
||||
vcmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
vcmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
//! Helper function for forcing a cache sync for all kernel parameters
|
||||
static void syncAllParams(amd::NDRangeKernelCommand& cmd)
|
||||
{
|
||||
const amd::Kernel& kernel = cmd.kernel();
|
||||
const amd::KernelParameters& kernelParam = kernel.parameters();
|
||||
const amd::KernelSignature& signature = kernel.signature();
|
||||
const amd::Device& device = cmd.queue()->device();
|
||||
|
||||
for (size_t i = 0; i < signature.numParameters(); ++i) {
|
||||
const amd::KernelParameterDescriptor& desc = signature.at(i);
|
||||
if (desc.type_ == T_POINTER && desc.size_ > 0 &&
|
||||
!kernelParam.boundToSvmPointer(device, cmd.parameters(), i)) {
|
||||
address ptr = (address) (cmd.parameters() + desc.offset_);
|
||||
amd::Memory* memArg = *(amd::Memory**)ptr;
|
||||
|
||||
if (memArg != NULL) {
|
||||
memArg->cacheWriteBack();
|
||||
memArg->signalWrite(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::computeLocalSizes(amd::NDRangeKernelCommand& command,
|
||||
amd::NDRange& local) {
|
||||
bool uniformSize = (OPENCL_MAJOR < 2) ||
|
||||
command.kernel().getDeviceKernel(device())->getUniformWorkGroupSize();
|
||||
|
||||
const amd::NDRangeContainer& sizes = command.sizes();
|
||||
const size_t numCores = device().info().maxComputeUnits_;
|
||||
|
||||
const size_t globalSize1D = sizes.global().product();
|
||||
const size_t targetNumOperations =
|
||||
std::min(globalSize1D, numCores * 4);
|
||||
size_t localSize1D =
|
||||
std::min(globalSize1D / targetNumOperations,
|
||||
device().info().maxWorkGroupSize_);
|
||||
|
||||
for (size_t i = 0; i < local.dimensions(); ++i) {
|
||||
const size_t globalSize = sizes.global()[i];
|
||||
size_t localSize =
|
||||
std::min(std::min(localSize1D, globalSize),
|
||||
device().info().maxWorkItemSizes_[i]);
|
||||
|
||||
// local must exactly divide global if uniform size is required
|
||||
// For non uniform size, we could use the work group size hint
|
||||
if (uniformSize && globalSize % localSize != 0) {
|
||||
while (true) {
|
||||
//! @todo: lmoriche: find a better way
|
||||
if (globalSize % localSize == 0) break;
|
||||
--localSize;
|
||||
}
|
||||
}
|
||||
local[i] = localSize;
|
||||
localSize1D /= localSize;
|
||||
}
|
||||
|
||||
command.setLocalWorkSize(local);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
amd::NDRange computeRemainders(const amd::NDRange& global,
|
||||
const amd::NDRange& local)
|
||||
{
|
||||
amd::NDRange remainders(local.dimensions());
|
||||
|
||||
for (size_t i = 0; i < local.dimensions(); ++i) {
|
||||
remainders[i] = (global[i] % local[i] != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
return remainders;
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitKernel(amd::NDRangeKernelCommand& command)
|
||||
{
|
||||
const amd::NDRangeContainer& sizes = command.sizes();
|
||||
const size_t numCores = device().info().maxComputeUnits_;
|
||||
|
||||
amd::NDRange local = sizes.local();
|
||||
|
||||
if (local == 0) {
|
||||
computeLocalSizes(command, local);
|
||||
}
|
||||
amd::NDRange remainders = computeRemainders(sizes.global(), local);
|
||||
|
||||
// number of groups in each dimensions
|
||||
const amd::NDRange numGroups = (sizes.global() / local) + remainders;
|
||||
|
||||
size_t numOperations = numGroups.product();
|
||||
if (numOperations == 0) {
|
||||
command.setStatus(CL_COMPLETE);
|
||||
return;
|
||||
}
|
||||
|
||||
syncAllParams(command);
|
||||
// retain the command here instead of retaining in NDRangeKernelBatch' ctor
|
||||
command.retain();
|
||||
|
||||
size_t batchCount = std::min(numOperations, numCores);
|
||||
NDRangeKernelBatch batch(command, *this, numGroups, batchCount);
|
||||
|
||||
Operation::Counter counter(command, batchCount);
|
||||
command.setData(&counter);
|
||||
|
||||
for (size_t coreId = 0; coreId < batchCount; ++coreId) {
|
||||
batch.setCoreId(coreId);
|
||||
cores_[coreId]->enqueue(batch);
|
||||
cores_[coreId]->flush();
|
||||
}
|
||||
|
||||
command.awaitCompletion();
|
||||
command.release();
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitNativeFn(amd::NativeFnCommand& command)
|
||||
{
|
||||
NativeFn fn(command);
|
||||
cores_[0]->enqueue(fn);
|
||||
cores_[0]->flush();
|
||||
command.awaitCompletion();
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitMarker(amd::Marker& command)
|
||||
{
|
||||
command.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitAcquireExtObjects(amd::AcquireExtObjectsCommand& cmd)
|
||||
{
|
||||
//! @todo [odintsov]: create an AcquireExtObjectsOperation and enqueue it
|
||||
//! to a core when a core scheduler is around.
|
||||
//
|
||||
// cores_[0]->enqueue(new AcquireExtObjectsOperation(cmd));
|
||||
// the code below will be moved to AcquireExtObjectsOperation::execute()
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
|
||||
//
|
||||
// AcquireExtObjects execution starts here
|
||||
//
|
||||
bool bError = false;
|
||||
|
||||
//! Go through ext objects by one and call member function to execute
|
||||
//! a sequence of external graphics API commands for each external object
|
||||
for(std::vector<amd::Memory*>::const_iterator itr = cmd.getMemList().begin();
|
||||
itr != cmd.getMemList().end(); itr++) {
|
||||
if(*itr) {
|
||||
bError |= !((*itr)->mapExtObjectInCQThread());
|
||||
}
|
||||
}
|
||||
if(bError) {
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitReleaseExtObjects(amd::ReleaseExtObjectsCommand& cmd)
|
||||
{
|
||||
//! @todo [odintsov]: create a ReleaseExtObjectsOperation and enqueue it
|
||||
//! to a core when a core scheduler is around.
|
||||
//
|
||||
// cores_[i]->enqueue(new ReleaseExtObjectsOperation(cmd));
|
||||
// the code below will be moved to ReleaseExtObjectsOperation::execute()
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
|
||||
bool bError = false;
|
||||
|
||||
for(std::vector<amd::Memory*>::const_iterator itr = cmd.getMemList().begin();
|
||||
itr != cmd.getMemList().end(); itr++) {
|
||||
if(*itr) {
|
||||
bError |= !((*itr)->unmapExtObjectInCQThread());
|
||||
}
|
||||
}
|
||||
if(bError) {
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
else {
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualCPU::submitPerfCounter(amd::PerfCounterCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
LogError("We don't support HW perf counters on CPU");
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void VirtualCPU::submitThreadTraceMemObjects(amd::ThreadTraceMemObjectsCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
LogError("We don't support thread trace on CPU");
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void VirtualCPU::submitThreadTrace(amd::ThreadTraceCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
LogError("We don't support thread trace on CPU");
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::flush(amd::Command* list, bool wait)
|
||||
{
|
||||
amd::Command* head = list;
|
||||
|
||||
// Release all commands from the link list
|
||||
while (head != NULL) {
|
||||
amd::Command * it = head->getNext();
|
||||
head->release();
|
||||
head = it;
|
||||
}
|
||||
}
|
||||
|
||||
#if cl_amd_open_video
|
||||
void VirtualCPU::submitRunVideoProgram(amd::RunVideoProgramCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void VirtualCPU::submitSetVideoSession(amd::SetVideoSessionCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
#endif // cl_amd_open_video
|
||||
|
||||
void
|
||||
VirtualCPU::submitSignal(amd::SignalCommand & cmd)
|
||||
{
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitMakeBuffersResident(amd::MakeBuffersResidentCommand & cmd)
|
||||
{
|
||||
cmd.setStatus(CL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitSvmFreeMemory(amd::SvmFreeMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
if (cmd.pfnFreeFunc() == NULL) {
|
||||
// pointers allocated using clSVMAlloc
|
||||
for (cl_uint i = 0; i < cmd.svmPointers().size(); i++) {
|
||||
amd::SvmBuffer::free(cmd.context(), cmd.svmPointers()[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cmd.pfnFreeFunc()(as_cl(cmd.queue()->asCommandQueue()), cmd.svmPointers().size(),
|
||||
(void**) (&(cmd.svmPointers()[0])), cmd.userData());
|
||||
}
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitSvmCopyMemory(amd::SvmCopyMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
amd::SvmBuffer::memFill(cmd.dst(), cmd.src(), cmd.srcSize(), 1);
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitSvmFillMemory(amd::SvmFillMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_RUNNING);
|
||||
amd::SvmBuffer::memFill(cmd.dst(), cmd.pattern(), cmd.patternSize(), cmd.times());
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitSvmMapMemory(amd::SvmMapMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
void
|
||||
VirtualCPU::submitSvmUnmapMemory(amd::SvmUnmapMemoryCommand& cmd)
|
||||
{
|
||||
cmd.setStatus(CL_COMPLETE);
|
||||
}
|
||||
|
||||
} // namespace cpu
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright (c) 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef CPUVIRTUAL_HPP_
|
||||
#define CPUVIRTUAL_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "platform/ndrange.hpp"
|
||||
|
||||
//! \namespace cpu CPU Device Implementation
|
||||
namespace cpu {
|
||||
|
||||
class WorkerThread;
|
||||
class Device;
|
||||
|
||||
class VirtualCPU : public device::VirtualDevice
|
||||
{
|
||||
private:
|
||||
WorkerThread** cores_; //!< Pointer to array of Worker threads
|
||||
static amd::Atomic<size_t> numWorkerThreads_; //!< Current Worker Threads number
|
||||
bool acceptingCommands_;
|
||||
|
||||
public:
|
||||
VirtualCPU(cpu::Device& device);
|
||||
~VirtualCPU();
|
||||
bool terminate();
|
||||
|
||||
WorkerThread* getWorkerThread(size_t id) { return cores_[id]; }
|
||||
|
||||
bool acceptingCommands() const { return acceptingCommands_; }
|
||||
|
||||
virtual void submitReadMemory(amd::ReadMemoryCommand& command);
|
||||
virtual void submitWriteMemory(amd::WriteMemoryCommand& command);
|
||||
virtual void submitCopyMemory(amd::CopyMemoryCommand& command);
|
||||
virtual void submitMapMemory(amd::MapMemoryCommand& command);
|
||||
virtual void submitUnmapMemory(amd::UnmapMemoryCommand& command);
|
||||
virtual void submitKernel(amd::NDRangeKernelCommand& command);
|
||||
virtual void submitNativeFn(amd::NativeFnCommand& command);
|
||||
virtual void submitMarker(amd::Marker& command);
|
||||
virtual void submitFillMemory(amd::FillMemoryCommand& command);
|
||||
virtual void submitMigrateMemObjects(amd::MigrateMemObjectsCommand& cmd) {}
|
||||
virtual void submitAcquireExtObjects(amd::AcquireExtObjectsCommand& cmd);
|
||||
virtual void submitReleaseExtObjects(amd::ReleaseExtObjectsCommand& cmd);
|
||||
virtual void submitPerfCounter(amd::PerfCounterCommand& cmd);
|
||||
virtual void submitThreadTraceMemObjects(amd::ThreadTraceMemObjectsCommand& cmd);
|
||||
virtual void submitThreadTrace(amd::ThreadTraceCommand& cmd);
|
||||
virtual void flush(amd::Command* list = NULL, bool wait = false);
|
||||
#if cl_amd_open_video
|
||||
virtual void submitRunVideoProgram(amd::RunVideoProgramCommand& cmd);
|
||||
virtual void submitSetVideoSession(amd::SetVideoSessionCommand& cmd);
|
||||
#endif // cl_amd_open_video
|
||||
virtual void submitSignal(amd::SignalCommand & cmd);
|
||||
virtual void submitMakeBuffersResident(amd::MakeBuffersResidentCommand & cmd);
|
||||
virtual void submitSvmFreeMemory(amd::SvmFreeMemoryCommand& cmd);
|
||||
virtual void submitSvmCopyMemory(amd::SvmCopyMemoryCommand& cmd);
|
||||
virtual void submitSvmFillMemory(amd::SvmFillMemoryCommand& cmd);
|
||||
virtual void submitSvmMapMemory(amd::SvmMapMemoryCommand& cmd);
|
||||
virtual void submitSvmUnmapMemory(amd::SvmUnmapMemoryCommand& cmd);
|
||||
|
||||
virtual void computeLocalSizes(amd::NDRangeKernelCommand& command,
|
||||
amd::NDRange& local);
|
||||
|
||||
static bool fillImage(
|
||||
amd::Image& image,
|
||||
address fillMem,
|
||||
const void* pattern,
|
||||
const amd::Coord3D& origin,
|
||||
const amd::Coord3D& region,
|
||||
size_t rowPitch,
|
||||
size_t slicePitch,
|
||||
size_t elementSize);
|
||||
};
|
||||
|
||||
} // namespace cpu
|
||||
|
||||
#endif // CPUVIRTUAL_HPP_
|
||||
@@ -0,0 +1,207 @@
|
||||
//
|
||||
// Copyright 2011 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef RING_BUFFER_HPP
|
||||
#define RING_BUFFER_HPP
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "os/alloc.hpp"
|
||||
// @brief Block-free ring buffer implemenation
|
||||
// @brief THE RING BUFFER SUPPORTS MULTIPLE CONSUMERS AND A SINGLE PRODUCER.
|
||||
// @tparam T Object-type to be saved within the ring buffer.
|
||||
namespace amd{
|
||||
template <typename T>
|
||||
class RingBuffer
|
||||
{
|
||||
public:
|
||||
///////////////////////////////////////
|
||||
// public initialization and cleanup //
|
||||
///////////////////////////////////////
|
||||
RingBuffer();
|
||||
~RingBuffer() { cleanup();}
|
||||
|
||||
bool
|
||||
initialize(unsigned short ringBufferSize);
|
||||
//////////////////////
|
||||
// public interface //
|
||||
///////////////////////
|
||||
|
||||
bool getNext(T & obj);
|
||||
bool insert(const T & obj);
|
||||
private:
|
||||
struct ABACounter{
|
||||
unsigned short tranactionId;
|
||||
unsigned short consumerIndex;
|
||||
};
|
||||
|
||||
union Consumer {
|
||||
ABACounter abaCounter;
|
||||
volatile int32_t interlockedVar;
|
||||
};
|
||||
|
||||
bool canInsert();
|
||||
|
||||
template <typename T2> T2 incrementIndex(T2 index) {
|
||||
index++;
|
||||
if (index == ringBufferSize_)
|
||||
index = 0;
|
||||
return index;
|
||||
}
|
||||
////////////////////////////////////
|
||||
// read only cache line for //
|
||||
// producer and consumer threads //
|
||||
////////////////////////////////////
|
||||
T * ringBuffer_;
|
||||
unsigned short ringBufferSize_;
|
||||
|
||||
char cachePad1_[64];
|
||||
/////////////////////////////////////
|
||||
// read/write cache line for //
|
||||
// producer thread //
|
||||
/////////////////////////////////////
|
||||
//! producer is an index in the ring buffer array
|
||||
volatile int32_t producer_;
|
||||
//! caches the amount of free space in the buffer. reduces cache misses
|
||||
//! by reducing access to 'm_consumer' from producer thread
|
||||
int32_t freeSpace_;
|
||||
|
||||
char cachePad2_[64];
|
||||
/////////////////////////////////////
|
||||
// read/write cache line for //
|
||||
// consumer threads //
|
||||
/////////////////////////////////////
|
||||
volatile Consumer consumer_;
|
||||
|
||||
/////////////////////////////////////
|
||||
// save the thread that inserts //
|
||||
// for checking multiple producers //
|
||||
/////////////////////////////////////
|
||||
Thread *producerThread_;
|
||||
|
||||
void cleanup();
|
||||
// do not allow copying
|
||||
RingBuffer(const RingBuffer&);
|
||||
RingBuffer& operator=(const RingBuffer&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
RingBuffer<T>::RingBuffer() :
|
||||
ringBuffer_(NULL),
|
||||
ringBufferSize_(0),
|
||||
producer_(0),
|
||||
freeSpace_(0),
|
||||
producerThread_(NULL)
|
||||
{
|
||||
consumer_.interlockedVar = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
RingBuffer<T>::initialize(unsigned short ringBufferSize)
|
||||
{
|
||||
bool retVal = false;
|
||||
|
||||
cleanup();
|
||||
ringBuffer_ = new T [ringBufferSize];
|
||||
if (ringBuffer_)
|
||||
{
|
||||
ringBufferSize_ = ringBufferSize;
|
||||
retVal = true;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
RingBuffer<T>::cleanup()
|
||||
{
|
||||
if (ringBuffer_)
|
||||
{
|
||||
delete [] ringBuffer_;
|
||||
ringBuffer_ = NULL;
|
||||
}
|
||||
producer_ = 0;
|
||||
consumer_.interlockedVar = 0;
|
||||
freeSpace_ = 0;
|
||||
ringBufferSize_ = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
RingBuffer<T>::insert(const T & obj)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// if this is the 1st insert, set producerThread_
|
||||
if (NULL == producerThread_) {
|
||||
producerThread_ = Thread::current();
|
||||
} else {
|
||||
assert(Thread::current() == producerThread_ && "not a single writer");
|
||||
}
|
||||
#endif //DEBUG
|
||||
bool retVal = false;
|
||||
if (canInsert())
|
||||
{
|
||||
ringBuffer_[producer_] = obj;
|
||||
|
||||
producer_ = incrementIndex(producer_);
|
||||
retVal = true;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
RingBuffer<T>::getNext( T & obj)
|
||||
{
|
||||
|
||||
Consumer consumer;
|
||||
consumer.interlockedVar = consumer_.interlockedVar;
|
||||
//cache the producer variable on the stack
|
||||
int producer = producer_;
|
||||
//while the buffer is not empty
|
||||
while (producer != consumer.abaCounter.consumerIndex)
|
||||
{
|
||||
obj = ringBuffer_[consumer.abaCounter.consumerIndex];
|
||||
Consumer newConsumer;
|
||||
newConsumer.abaCounter.consumerIndex = incrementIndex(consumer.abaCounter.consumerIndex);
|
||||
newConsumer.abaCounter.tranactionId = consumer.abaCounter.tranactionId+1;
|
||||
|
||||
if (consumer.interlockedVar == amd::AtomicOperation::compareAndSwap(consumer.interlockedVar,
|
||||
&(consumer_.interlockedVar),newConsumer.interlockedVar))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
consumer.interlockedVar = consumer_.interlockedVar;
|
||||
producer = producer_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
RingBuffer<T>::canInsert()
|
||||
{
|
||||
if (freeSpace_ > 1)
|
||||
{
|
||||
freeSpace_--;
|
||||
return true;
|
||||
}
|
||||
//cache the volatile variable on the stack;
|
||||
int32_t consumer = consumer_.abaCounter.consumerIndex;
|
||||
|
||||
//there will alway be one unused cell in the array
|
||||
//to distinguish between the case it is completely full and completely empty
|
||||
freeSpace_ = consumer - producer_ - 1 ;
|
||||
if ( freeSpace_ <= -1 )
|
||||
{
|
||||
freeSpace_ = ringBufferSize_ + freeSpace_;
|
||||
}
|
||||
return (freeSpace_ > 0) ;
|
||||
}
|
||||
|
||||
}//NAMESPACE AMD
|
||||
|
||||
#endif // RING_BUFFER_HPP
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "top.hpp"
|
||||
#include "utils/debug.hpp"
|
||||
#include "device/appprofile.hpp"
|
||||
#include "device/gpu/gpuappprofile.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
AppProfile::AppProfile():amd::AppProfile(),
|
||||
enableHighPerformanceState_(IS_LINUX ? false : true),
|
||||
reportAsOCL12Device_(false)
|
||||
{
|
||||
propertyDatatypeMap_.insert(DatatypeMap::value_type("HighPerfState",
|
||||
DataType_Boolean));
|
||||
boolPropertyMap_.insert(BoolMap::value_type("HighPerfState",
|
||||
&enableHighPerformanceState_));
|
||||
|
||||
propertyDatatypeMap_.insert(DatatypeMap::value_type("OCL12Device",
|
||||
DataType_Boolean));
|
||||
boolPropertyMap_.insert(BoolMap::value_type("OCL12Device",
|
||||
&reportAsOCL12Device_));
|
||||
}
|
||||
|
||||
bool AppProfile::ParseApplicationProfile()
|
||||
{
|
||||
amd::ADL *adl = new amd::ADL;
|
||||
|
||||
if (!adl->init()) {
|
||||
delete adl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int result = ADL_ERR_NOT_INIT;
|
||||
ADLApplicationProfile *pProfile = NULL;
|
||||
|
||||
//
|
||||
// Apply blb configurations
|
||||
//
|
||||
result = adl->adl2ApplicationProfilesProfileOfApplicationx2Search(adl->adlContext(),
|
||||
wsAppFileName_.c_str(),
|
||||
NULL,
|
||||
NULL,
|
||||
L"OCL",
|
||||
&pProfile);
|
||||
|
||||
delete adl;
|
||||
|
||||
if (pProfile == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PropertyRecord *firstProperty = pProfile->record;
|
||||
PropertyRecord *profileProperty = NULL;
|
||||
uint32_t valueOffset = 0;
|
||||
for (int index = 0; index < pProfile->iCount; index++) {
|
||||
profileProperty = reinterpret_cast<PropertyRecord*>
|
||||
((reinterpret_cast<char*>(firstProperty)) + valueOffset);
|
||||
|
||||
//
|
||||
// Get property name
|
||||
//
|
||||
char* propertyName = profileProperty->strName;
|
||||
DatatypeMap::const_iterator propertyDatatypeMapIt =
|
||||
propertyDatatypeMap_.find(std::string(propertyName));
|
||||
if (propertyDatatypeMapIt == propertyDatatypeMap_.end())
|
||||
{
|
||||
valueOffset += (sizeof(PropertyRecord) + profileProperty->iDataSize - 4);
|
||||
continue; // unexpected name.
|
||||
}
|
||||
|
||||
DataTypes dataType = propertyDatatypeMapIt->second;
|
||||
switch(dataType) {
|
||||
case DataType_Boolean:
|
||||
{
|
||||
unsigned char propertyValue = profileProperty->uData[0];
|
||||
BoolMap::iterator boolPropertyMapIt =
|
||||
boolPropertyMap_.find(std::string(propertyName));
|
||||
if (boolPropertyMapIt != boolPropertyMap_.end()) {
|
||||
*(boolPropertyMapIt->second) = propertyValue ? true : false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
valueOffset += (sizeof(PropertyRecord) + profileProperty->iDataSize - 4);
|
||||
}
|
||||
|
||||
free(pProfile);
|
||||
pProfile = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUAPPPROFILE_HPP_
|
||||
#define GPUAPPPROFILE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class AppProfile : public amd::AppProfile
|
||||
{
|
||||
public:
|
||||
AppProfile();
|
||||
|
||||
//! return the value of enableHighPerformanceState_
|
||||
bool enableHighPerformanceState() const {return enableHighPerformanceState_; }
|
||||
bool reportAsOCL12Device() const {return reportAsOCL12Device_; }
|
||||
|
||||
protected:
|
||||
//! parse application profile based on application file name
|
||||
virtual bool ParseApplicationProfile();
|
||||
|
||||
private:
|
||||
typedef enum DataTypesEnum
|
||||
{
|
||||
DataType_Unknown = 0,
|
||||
DataType_Boolean,
|
||||
} DataTypes;
|
||||
typedef std::map<std::string, DataTypes> DatatypeMap;
|
||||
typedef std::map<std::string, bool*> BoolMap;
|
||||
|
||||
DatatypeMap propertyDatatypeMap_;
|
||||
BoolMap boolPropertyMap_;
|
||||
|
||||
bool enableHighPerformanceState_;
|
||||
bool reportAsOCL12Device_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,548 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gpubinary.hpp"
|
||||
#include "device/gpu/gpuprogram.hpp"
|
||||
#include "utils/options.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
enum {
|
||||
NDX_KERNEL = 0,
|
||||
NDX_METADATA = 1,
|
||||
NDX_HEADER = 2,
|
||||
NDX_AMDIL = 3,
|
||||
NDX_LAST
|
||||
};
|
||||
typedef struct {
|
||||
bool IsKernel; // whether the entry is for kernel
|
||||
|
||||
/*
|
||||
SymInfo[NDX_KERNEL] : SymbolInfo for kernel isa (cal image)
|
||||
SymInfo[NDX_METADATA] : SymbolInfo for kernel metadata
|
||||
SymInfo[NDX_HEADER] : SymbolInfo for kernel header
|
||||
SymInfo[NDX_AMDIL] : SymbolInfo for kernel's amdil
|
||||
*/
|
||||
amd::OclElf::SymbolInfo SymInfo[NDX_LAST];
|
||||
} ElfSymbol_t;
|
||||
|
||||
}
|
||||
|
||||
namespace gpu {
|
||||
|
||||
bool
|
||||
ClBinary::loadKernels(NullProgram& program, bool* hasRecompiled)
|
||||
{
|
||||
const char __OpenCL_[] = "__OpenCL_";
|
||||
const char _kernel[] = "_kernel";
|
||||
const char _data[] = "_metadata"; // metadata for kernel function
|
||||
const char _fdata[] = "_fmetadata"; // metadata for non-kernel function
|
||||
const char _header[] = "_header";
|
||||
const char _amdil[] = "_amdil";
|
||||
|
||||
*hasRecompiled = false;
|
||||
|
||||
// TODO : jugu
|
||||
// Target should be 15 bit maximum. Should check this somewhere.
|
||||
uint32_t target = static_cast<uint32_t>(dev().calTarget());
|
||||
uint16_t elf_target;
|
||||
amd::OclElf::oclElfPlatform platform;
|
||||
if (!elfIn()->getTarget(elf_target, platform)) {
|
||||
LogError("The OCL binary image loading failed: incorrect format");
|
||||
return false;
|
||||
}
|
||||
if (platform == amd::OclElf::COMPLIB_PLATFORM) {
|
||||
// BIF 3.0
|
||||
uint32_t flag;
|
||||
aclTargetInfo tgtInfo = aclGetTargetInfo("amdil", dev().hwInfo()->targetName_, NULL);
|
||||
if (!elfIn()->getFlags(flag)){
|
||||
LogError("The OCL binary image loading failed: incorrect format");
|
||||
return false;
|
||||
}
|
||||
if ((elf_target != EM_AMDIL) ||
|
||||
(tgtInfo.chip_id != flag)) {
|
||||
LogError("The OCL binary image loading failed: different target");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((platform != amd::OclElf::CAL_PLATFORM) ||
|
||||
((uint32_t)target != elf_target))) {
|
||||
LogError("The OCL binary image loading failed: different target");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Using class so that dtor() can be invoked to do clean-up */
|
||||
class TempWrapper {
|
||||
public:
|
||||
/*
|
||||
functionNameMap[] maps from a function name (linkage name in the generated code)
|
||||
to ElfSymbol_t, which is defined as above.
|
||||
*/
|
||||
std::map<std::string, ElfSymbol_t*> functionNameMap;
|
||||
|
||||
// Keep all kernel ILs if -use-debugil is present (gpu debugging)
|
||||
std::map<std::string, std::string> kernelILs;
|
||||
|
||||
~TempWrapper () {
|
||||
std::map<std::string, ElfSymbol_t*>::iterator
|
||||
I, IB = functionNameMap.begin(), IE = functionNameMap.end();
|
||||
for (I = IB; I != IE; ++I) {
|
||||
delete [] (*I).second;
|
||||
}
|
||||
|
||||
kernelILs.clear();
|
||||
}
|
||||
} tempObj;
|
||||
|
||||
/*
|
||||
If usedebugil is true, we will load IL from .debugil section. We will ignore
|
||||
_kernel, _amdil, _header in the binary.
|
||||
*/
|
||||
bool usedebugil = program.getCompilerOptions()->oVariables->UseDebugIL;
|
||||
|
||||
for (amd::Sym_Handle sym = elfIn()->nextSymbol(NULL);
|
||||
sym != NULL;
|
||||
sym = elfIn()->nextSymbol(sym)) {
|
||||
amd::OclElf::SymbolInfo symInfo;
|
||||
if (!elfIn()->getSymbolInfo(sym, &symInfo)) {
|
||||
LogError("LoadKernelFromElf: getSymbolInfo() fails");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string elfSymName(symInfo.sym_name);
|
||||
const size_t offset = sizeof(__OpenCL_) - 1;
|
||||
if (elfSymName.compare(0, offset, __OpenCL_) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Assume this elfSymName is associated with a kernel name. The following code will adjust
|
||||
// it if it isn't.
|
||||
const size_t suffixPos = elfSymName.rfind('_');
|
||||
bool isKernel = true; // assume it is a kernel
|
||||
std::string FName = elfSymName.substr(0, suffixPos);
|
||||
FName.append("_kernel"); // make the kernel's linkage name
|
||||
|
||||
ElfSymbol_t* elfsymbol = tempObj.functionNameMap[FName];
|
||||
amd::OclElf::SymbolInfo* sinfo = (elfsymbol != NULL) ? &(elfsymbol->SymInfo[0]) : NULL;
|
||||
|
||||
// Add info for this elf symbol into tempobj's functionNameMap[]
|
||||
int index = -1;
|
||||
if (!usedebugil &&
|
||||
(elfSymName.compare(suffixPos, sizeof(_kernel) - 1, _kernel) == 0)) {
|
||||
index = NDX_KERNEL;
|
||||
assert (((sinfo == NULL) || (sinfo[index].size == 0)) &&
|
||||
"More than one kernel symbol for the same kernel");
|
||||
}
|
||||
else if (!usedebugil &&
|
||||
(elfSymName.compare(suffixPos, sizeof(_header) - 1, _header) == 0)) {
|
||||
index = NDX_HEADER;
|
||||
assert (((sinfo == NULL) || (sinfo[index].size == 0)) &&
|
||||
"More than one header symbol for a kernel");
|
||||
}
|
||||
else if (!usedebugil &&
|
||||
(elfSymName.compare(suffixPos, sizeof(_amdil) - 1, _amdil) == 0)) {
|
||||
index = NDX_AMDIL;
|
||||
assert (((sinfo == NULL) || (sinfo[index].size == 0)) &&
|
||||
"More than one amdil symbol for a kernel");
|
||||
}
|
||||
else if (elfSymName.compare(suffixPos, sizeof(_data) - 1, _data) == 0) {
|
||||
index = NDX_METADATA;
|
||||
assert (((sinfo == NULL) || (sinfo[index].size == 0)) &&
|
||||
"More than one metadata symbol for the same kernel");
|
||||
}
|
||||
else if (elfSymName.compare(suffixPos, sizeof(_fdata) - 1, _fdata) == 0) {
|
||||
index = NDX_METADATA;
|
||||
isKernel = false;
|
||||
|
||||
FName = elfSymName.substr(offset, suffixPos - offset);
|
||||
|
||||
elfsymbol = tempObj.functionNameMap[FName];
|
||||
sinfo = (elfsymbol != NULL) ? &(elfsymbol->SymInfo[0]) : NULL;
|
||||
|
||||
assert (((sinfo == NULL) || (sinfo[index].size == 0)) &&
|
||||
"More than one metadata symbol for a non-kernel function");
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
if (elfsymbol == NULL) {
|
||||
elfsymbol = new ElfSymbol_t();
|
||||
sinfo = &(elfsymbol->SymInfo[0]);
|
||||
::memset(sinfo, 0, NDX_LAST * sizeof(amd::OclElf::SymbolInfo));
|
||||
tempObj.functionNameMap[FName] = elfsymbol;
|
||||
|
||||
elfsymbol->IsKernel = isKernel;
|
||||
}
|
||||
sinfo[index] = symInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (usedebugil) {
|
||||
std::string programil;
|
||||
char *section;
|
||||
size_t sz;
|
||||
|
||||
if (elfIn_->getSection(amd::OclElf::ILDEBUG, §ion, &sz)) {
|
||||
// Get debugIL
|
||||
programil.append(section, sz);
|
||||
}
|
||||
else {
|
||||
LogError("LoadKernelFromElf(): reading .debugil failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append all function metadata to debugIL
|
||||
std::map<std::string, ElfSymbol_t*>::iterator
|
||||
I, IB = tempObj.functionNameMap.begin(), IE = tempObj.functionNameMap.end();
|
||||
for (I = IB; I != IE; ++I) {
|
||||
ElfSymbol_t* elfsymbol = (*I).second;
|
||||
if (elfsymbol == NULL) {
|
||||
// Not valid, skip
|
||||
continue;
|
||||
}
|
||||
if ( (elfsymbol->SymInfo[NDX_METADATA].address != 0) &&
|
||||
(elfsymbol->SymInfo[NDX_METADATA].size > 0) ) {
|
||||
std::string mdString = std::string(elfsymbol->SymInfo[NDX_METADATA].address,
|
||||
elfsymbol->SymInfo[NDX_METADATA].size);
|
||||
assert ((mdString.find_first_of('\0') == std::string::npos) &&
|
||||
"Metadata string has NULL inside !");
|
||||
programil.append(mdString);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ilKernelName =
|
||||
program.getCompilerOptions()->oVariables->JustKernel;
|
||||
if (!program.getAllKernelILs(tempObj.kernelILs, programil, ilKernelName)) {
|
||||
LogError("LoadKernelFromElf(): MDParser failed generating kernel ILs");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, patch the IL from debugIL into functionNameMap[]
|
||||
std::map<std::string, std::string>::iterator
|
||||
KI, KIB = tempObj.kernelILs.begin(), KIE = tempObj.kernelILs.end();
|
||||
for (KI = KIB; KI != KIE; ++KI) {
|
||||
const std::string& kn = (*KI).first;
|
||||
const std::string& ilstr = (*KI).second;
|
||||
|
||||
ElfSymbol_t* elfsymbol = tempObj.functionNameMap[kn];
|
||||
if (elfsymbol == NULL) {
|
||||
elfsymbol = new ElfSymbol_t();
|
||||
::memset(elfsymbol->SymInfo, 0, NDX_LAST * sizeof(amd::OclElf::SymbolInfo));
|
||||
tempObj.functionNameMap[kn] = elfsymbol;
|
||||
}
|
||||
amd::OclElf::SymbolInfo* sinfo = &(elfsymbol->SymInfo[0]);
|
||||
|
||||
elfsymbol->IsKernel = true;
|
||||
sinfo[NDX_AMDIL].address = const_cast<char*>(ilstr.data());
|
||||
sinfo[NDX_AMDIL].size = ilstr.size();
|
||||
// All the other fields in SymInfo is unused
|
||||
}
|
||||
}
|
||||
|
||||
bool recompiled = false;
|
||||
bool hasKernels = false;
|
||||
std::map<std::string, ElfSymbol_t*>::iterator
|
||||
I, IB = tempObj.functionNameMap.begin(), IE = tempObj.functionNameMap.end();
|
||||
for (I = IB; I != IE; ++I) {
|
||||
ElfSymbol_t* elfsymbol = (*I).second;
|
||||
if (elfsymbol == NULL) {
|
||||
// Not valid, skip
|
||||
continue;
|
||||
}
|
||||
else if (!elfsymbol->IsKernel) {
|
||||
// Not a kernel. Add its metadata to the OCL binary in case recompilation happens
|
||||
// and the new binary is needed.
|
||||
if (saveAMDIL()&&
|
||||
(elfsymbol->SymInfo[NDX_METADATA].size > 0)) {
|
||||
std::string fmetadata = "__OpenCL_";
|
||||
fmetadata.append((*I).first);
|
||||
fmetadata.append("_fmetadata");
|
||||
|
||||
if (!elfOut()->addSymbol(amd::OclElf::RODATA, fmetadata.c_str(),
|
||||
elfsymbol->SymInfo[NDX_METADATA].address,
|
||||
elfsymbol->SymInfo[NDX_METADATA].size)) {
|
||||
LogError ("AddSymbol() failed to add fmetadata");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
amd::OclElf::SymbolInfo* sinfo = &(elfsymbol->SymInfo[0]);
|
||||
std::string FName = (*I).first;
|
||||
|
||||
// For this kernel, get the demangled kernel name, which is used to identify each kernel.
|
||||
const size_t name_sz = FName.size() - (sizeof(_kernel) - 1) - (sizeof(__OpenCL_) - 1);
|
||||
std::string demangledKName = FName.substr(sizeof(__OpenCL_) - 1, name_sz);
|
||||
|
||||
// Check if the current entry is valid
|
||||
if (((sinfo[NDX_HEADER].size <= 0) || (sinfo[NDX_KERNEL].size <= 0)) &&
|
||||
(sinfo[NDX_AMDIL].size <= 0)) {
|
||||
std::string tlog = "Warning: both IL and CAL Image are not available for kernel " +
|
||||
demangledKName;
|
||||
LogWarning (tlog.c_str());
|
||||
continue;
|
||||
}
|
||||
hasKernels = true;
|
||||
|
||||
Kernel::InitData initData = {0};
|
||||
std::string ilSource(sinfo[NDX_AMDIL].address, sinfo[NDX_AMDIL].size);
|
||||
std::string metadata(sinfo[NDX_METADATA].address, sinfo[NDX_METADATA].size);
|
||||
if ((sinfo[NDX_HEADER].size <= 0) || (sinfo[NDX_KERNEL].size <= 0)) {
|
||||
// IL recompilation
|
||||
// TODO: global data recompilation as well.
|
||||
// 1) parse IL; 2) parse metadata to set up kernel header
|
||||
size_t pos;
|
||||
if (!program.findAllILFuncs(ilSource, pos)) {
|
||||
program.freeAllILFuncs();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFailed = false;
|
||||
for (uint32_t i=0; i < program.funcs_.size(); ++i) {
|
||||
ILFunc *func = program.funcs_[i];
|
||||
ElfSymbol_t *sym = tempObj.functionNameMap[func->name_];
|
||||
if (sym == NULL) {
|
||||
// No metadata for this function.
|
||||
continue;
|
||||
}
|
||||
|
||||
assert ((func->metadata_.end_ == 0) && "ILFunc init failed");
|
||||
amd::OclElf::SymbolInfo* si = &(sym->SymInfo[0]);
|
||||
if (si[NDX_METADATA].size > 0) {
|
||||
std::string meta(si[NDX_METADATA].address, si[NDX_METADATA].size);
|
||||
if (!program.parseFuncMetadata(meta, 0, std::string::npos)) {
|
||||
isFailed = true;
|
||||
break;
|
||||
}
|
||||
if (func->metadata_.end_ != std::string::npos) {
|
||||
assert( false && "ILFunc name and index does not match");
|
||||
isFailed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Accumulate all emulated local, region and private sizes,
|
||||
// necessary for the kernel execution
|
||||
initData.localSize_ += func->localSize_;
|
||||
initData.privateSize_ += func->privateSize_;
|
||||
|
||||
// Accumulate all HW local, region and private sizes,
|
||||
// necessary for the kernel execution
|
||||
initData.hwLocalSize_ += func->hwLocalSize_;
|
||||
initData.hwPrivateSize_ += func->hwPrivateSize_;
|
||||
initData.flags_ |= func->flags_;
|
||||
}
|
||||
}
|
||||
|
||||
program.freeAllILFuncs();
|
||||
if (isFailed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
KernelHeaderSymbol kHeader = {0};
|
||||
::memcpy(&kHeader, sinfo[NDX_HEADER].address,
|
||||
(sizeof(kHeader) < sinfo[NDX_HEADER].size)
|
||||
? sizeof(kHeader)
|
||||
: sinfo[NDX_HEADER].size);
|
||||
|
||||
if (kHeader.version_ > VERSION_CURRENT) {
|
||||
LogError("LoadKernelFromElf: cannot handle the newer version of the binary");
|
||||
return false;
|
||||
}
|
||||
|
||||
// VERSION_0
|
||||
initData.localSize_ = kHeader.localSize_;
|
||||
initData.hwLocalSize_ = kHeader.hwLocalSize_;
|
||||
initData.privateSize_ = kHeader.privateSize_;
|
||||
initData.hwPrivateSize_ = kHeader.hwPrivateSize_;
|
||||
initData.flags_ = kHeader.flags_;
|
||||
}
|
||||
|
||||
bool created;
|
||||
NullKernel* gpuKernel = program.createKernel(demangledKName, &initData, ilSource, metadata,
|
||||
&created, sinfo[NDX_KERNEL].address, sinfo[NDX_KERNEL].size);
|
||||
if (!created) {
|
||||
std::string tlog = "Error: Creating kernel during loading OCL binary " +
|
||||
demangledKName + " failed!";
|
||||
LogError(tlog.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
recompiled = recompiled || (sinfo[NDX_KERNEL].size == 0);
|
||||
|
||||
// Add the current kernel to the OCL binary in case recompilation happens and
|
||||
// the new binary is needed.
|
||||
if (!storeKernel(demangledKName, gpuKernel, &initData, metadata, ilSource)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*hasRecompiled = recompiled;
|
||||
return hasKernels;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::storeKernel(
|
||||
const std::string& name,
|
||||
const NullKernel* nullKernel,
|
||||
Kernel::InitData* initData,
|
||||
const std::string& metadata,
|
||||
const std::string& ilSource)
|
||||
{
|
||||
if (!saveISA() && !saveAMDIL()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// should we save kernel metadata only under saveAMDIL()?
|
||||
bool kernelMetaStored = false;
|
||||
|
||||
if (saveAMDIL() && (ilSource.size() > 0)) {
|
||||
// Save IL (this is the per-kernel IL)
|
||||
std::string ilName = "__OpenCL_" + name + "_amdil";
|
||||
if (!elfOut()->addSymbol(amd::OclElf::ILTEXT, ilName.c_str(),
|
||||
ilSource.data(), ilSource.size())) {
|
||||
LogError ("AddElfSymbol failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string metaName = "__OpenCL_" + name + "_metadata";
|
||||
// Save metadata symbols in .rodata
|
||||
if (!elfOut()->addSymbol(amd::OclElf::RODATA, metaName.c_str(),
|
||||
metadata.data(), metadata.size())) {
|
||||
LogError ("AddElfSymbol failed");
|
||||
return false;
|
||||
}
|
||||
kernelMetaStored = true;
|
||||
}
|
||||
|
||||
if (!saveISA()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t binarySize = (nullKernel != NULL) ? nullKernel->getCalBinarySize() : 0;
|
||||
if (binarySize != 0) {
|
||||
if (!kernelMetaStored) {
|
||||
std::string metaName = "__OpenCL_" + name + "_metadata";
|
||||
// Save metadata symbols in .rodata
|
||||
if (!elfOut()->addSymbol(amd::OclElf::RODATA, metaName.c_str(),
|
||||
metadata.data(), metadata.size())) {
|
||||
LogError ("AddSymbol failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Save kernel symbol that is associated with GPU ISA
|
||||
std::string kernelName = "__OpenCL_" + name + "_kernel";
|
||||
uint8_t* isacode = new uint8_t[binarySize];
|
||||
if (!nullKernel->getCalBinary(
|
||||
reinterpret_cast<void*>(isacode), binarySize)) {
|
||||
LogError("Failed to read GPU kernel isa");
|
||||
delete [] isacode;
|
||||
return false;
|
||||
}
|
||||
if (!elfOut()->addSymbol(amd::OclElf::CAL, kernelName.c_str(),
|
||||
isacode, binarySize)) {
|
||||
LogError ("AddElfSymbol failed");
|
||||
return false;
|
||||
}
|
||||
delete [] isacode;
|
||||
|
||||
// Save kernel header information into a pseudo symbol
|
||||
// __OpenCL_<kernelName>_header
|
||||
// for example, given a kernel foo, this pseudo symbol
|
||||
// would be __OpenCL_foo_header
|
||||
std::string headerName = "__OpenCL_" + name + "_header";
|
||||
KernelHeaderSymbol kHeader;
|
||||
// VERSION_0
|
||||
kHeader.privateSize_ = initData->privateSize_;
|
||||
kHeader.localSize_ = initData->localSize_;
|
||||
kHeader.regionSize_ = 0;
|
||||
kHeader.hwPrivateSize_ = initData->hwPrivateSize_;
|
||||
kHeader.hwLocalSize_ = initData->hwLocalSize_;
|
||||
kHeader.hwRegionSize_ = 0;
|
||||
kHeader.flags_ = initData->flags_;
|
||||
|
||||
// VERSION_1
|
||||
kHeader.version_ = VERSION_CURRENT;
|
||||
|
||||
if (!elfOut()->addSymbol(amd::OclElf::RODATA, headerName.c_str(),
|
||||
&kHeader, sizeof(kHeader))) {
|
||||
LogError("AddElfSymbol failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::loadGlobalData(Program& program)
|
||||
{
|
||||
const char __OpenCL_[] = "__OpenCL_";
|
||||
const char _global[] = "_global";
|
||||
|
||||
for (amd::Sym_Handle sym = elfIn()->nextSymbol(NULL);
|
||||
sym != NULL;
|
||||
sym = elfIn()->nextSymbol(sym)) {
|
||||
amd::OclElf::SymbolInfo symInfo;
|
||||
if (!elfIn()->getSymbolInfo(sym, &symInfo)) {
|
||||
LogError("LoadGlobalDataFromElf: getSymbolInfo() fails");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string globalName(symInfo.sym_name);
|
||||
const size_t offset = sizeof(__OpenCL_) - 1;
|
||||
if (globalName.compare(0, offset, __OpenCL_) != 0) {
|
||||
continue;
|
||||
}
|
||||
const size_t suffixPos = globalName.rfind('_');
|
||||
if (globalName.compare(suffixPos, sizeof(_global) - 1, _global) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get index for this global
|
||||
std::string indexString = globalName.substr(offset, suffixPos - offset);
|
||||
uint index = ::atoi(indexString.c_str());
|
||||
|
||||
if (!program.allocGlobalData(symInfo.address, symInfo.size, index)) {
|
||||
LogError("Couldn't load global data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::storeGlobalData(const void* globalData, size_t dataSize, uint index)
|
||||
{
|
||||
// For each global, use "__OpenCL_<globalname>" as its name
|
||||
// Since there is no name in amdil, just use "__OpenCL_<index>_global" for now.
|
||||
std::stringstream glbName;
|
||||
glbName << "__OpenCL_" << index << "_global";
|
||||
|
||||
if (!elfOut()->addSymbol(amd::OclElf::RODATA, glbName.str().c_str(),
|
||||
globalData, dataSize)) {
|
||||
LogError("addSymbol() failed");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ClBinary::clearElfOut()
|
||||
{
|
||||
// Recreate libelf elf object
|
||||
if (!elfOut()->Clear()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Need to re-setup target
|
||||
return setElfTarget();
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUBINARY_HPP_
|
||||
#define GPUBINARY_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class ClBinary : public device::ClBinary
|
||||
{
|
||||
public:
|
||||
|
||||
#pragma pack(push, 8)
|
||||
// Kernel version in the ELF header symbol
|
||||
enum KernelVersions {
|
||||
VERSION_0 = 0,
|
||||
VERSION_1,
|
||||
VERSION_CURRENT = VERSION_1
|
||||
};
|
||||
|
||||
/* This is the ELF header symbol */
|
||||
struct KernelHeaderSymbol {
|
||||
/* VERSION_0
|
||||
Version 0 has 8 uint32_t (32 bytes), top 5 are used, the rest zero'ed.
|
||||
In Version_0, KernelHeaderSymbol is the same as KernelHeader
|
||||
*/
|
||||
uint32_t privateSize_; //!< Emulated private memory size
|
||||
uint32_t localSize_; //!< Emulated local memory size
|
||||
uint32_t hwPrivateSize_; //!< HW private memory size
|
||||
uint32_t hwLocalSize_; //!< HW local memory size
|
||||
uint32_t flags_; //!< Kernel's flags
|
||||
|
||||
/* VERSION_1
|
||||
VERSION_1 has 6 uint32_t.
|
||||
*/
|
||||
uint32_t version_; //!< Kernel's version
|
||||
uint32_t regionSize_; //!< Region memory size
|
||||
uint32_t hwRegionSize_; //!< HW region memory size
|
||||
|
||||
/* New entries can be added here, do not change the previous entries */
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
//! Constructor
|
||||
ClBinary(const NullDevice& dev)
|
||||
: device::ClBinary(dev)
|
||||
{}
|
||||
|
||||
//! Destructor
|
||||
~ClBinary() {}
|
||||
|
||||
//! Creates and loads kernels from the OCL ELF binary file into the program
|
||||
bool loadKernels(
|
||||
NullProgram& program, //!< Program object with the binary
|
||||
bool* hasRecompiled //!< Recompile amdil to isa.
|
||||
);
|
||||
|
||||
//! Stores compiled kernel into the OCL ELF binary file
|
||||
bool storeKernel(
|
||||
const std::string& name, //!< Kernel's name
|
||||
const NullKernel* nullKernel, //!< The kernel to add
|
||||
Kernel::InitData* initData, //!< Kernel init data
|
||||
const std::string& metadata, //!< Kernel's metadata
|
||||
const std::string& ilSource //!< IL source text
|
||||
);
|
||||
|
||||
//! Loads the program's global data
|
||||
bool loadGlobalData(
|
||||
Program& program //!< The program object for the global data load
|
||||
);
|
||||
|
||||
//! Stores the program's global data
|
||||
bool storeGlobalData(
|
||||
const void* globalData, //!< The program global data
|
||||
size_t dataSize, //!< The program global data size
|
||||
uint index //!< The global data storage index
|
||||
);
|
||||
|
||||
//! Set elf header information for GPU target
|
||||
bool setElfTarget() {
|
||||
uint32_t target = static_cast<uint32_t>(dev().calTarget());
|
||||
assert (((0xFFFF8000 & target) == 0) && "ASIC target ID >= 2^15");
|
||||
uint16_t elf_target = (uint16_t)(0x7FFF & target);
|
||||
return elfOut()->setTarget(elf_target, amd::OclElf::CAL_PLATFORM);
|
||||
}
|
||||
|
||||
//! Clear elf out.
|
||||
bool clearElfOut();
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
ClBinary(const ClBinary&);
|
||||
|
||||
//! Disable default operator=
|
||||
ClBinary& operator=(const ClBinary&);
|
||||
|
||||
//! Returns the GPU device for this object
|
||||
const NullDevice& dev() const { return static_cast<const NullDevice&>(dev_); }
|
||||
|
||||
};
|
||||
|
||||
class ClBinaryHsa : public device::ClBinary
|
||||
{
|
||||
public:
|
||||
ClBinaryHsa(const Device& dev, BinaryImageFormat bifVer = BIF_VERSION3)
|
||||
: device::ClBinary(dev, bifVer)
|
||||
{}
|
||||
|
||||
//! Destructor
|
||||
~ClBinaryHsa() {}
|
||||
|
||||
|
||||
protected:
|
||||
bool setElfTarget() {
|
||||
uint32_t target = static_cast<uint32_t>(21);//dev().calTarget());
|
||||
assert (((0xFFFF8000 & target) == 0) && "ASIC target ID >= 2^15");
|
||||
uint16_t elf_target = (uint16_t)(0x7FFF & target);
|
||||
return elfOut()->setTarget(elf_target, amd::OclElf::CAL_PLATFORM);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
ClBinaryHsa(const ClBinaryHsa&);
|
||||
|
||||
//! Disable default operator=
|
||||
ClBinaryHsa& operator=(const ClBinaryHsa&);
|
||||
|
||||
//! Returns the HSA device for this object
|
||||
const Device& dev() const { return static_cast<const Device&>(dev_); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPUBINARY_HPP_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,453 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUBLIT_HPP_
|
||||
#define GPUBLIT_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/blit.hpp"
|
||||
|
||||
/*! \addtogroup GPU Blit Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Blit Manager Implementation
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class Kernel;
|
||||
class Resource;
|
||||
class Memory;
|
||||
class VirtualGPU;
|
||||
|
||||
//! DMA Blit Manager
|
||||
class DmaBlitManager : public device::HostBlitManager
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
DmaBlitManager(
|
||||
VirtualGPU& gpu, //!< Virtual GPU to be used for blits
|
||||
Setup setup = Setup() //!< Specifies HW accelerated blits
|
||||
);
|
||||
|
||||
//! Destructor
|
||||
virtual ~DmaBlitManager() {}
|
||||
|
||||
//! Creates DmaBlitManager object
|
||||
virtual bool create(amd::Device& device) { return true; }
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destinaiton host memory
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies an image object to system memory
|
||||
virtual bool readImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBuffer(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBufferRect(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to an image object
|
||||
virtual bool writeImage(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& srcRect, //!< Source rectangle
|
||||
const amd::BufferRect& dstRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies an image object to a buffer object
|
||||
virtual bool copyImageToBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
virtual bool copyBufferToImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies an image object to another image object
|
||||
virtual bool copyImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
protected:
|
||||
const static uint MaxPinnedBuffers = 4;
|
||||
|
||||
//! Synchronizes the blit operations if necessary
|
||||
inline void synchronize() const;
|
||||
|
||||
//! Returns the virtual GPU object
|
||||
VirtualGPU& gpu() const { return static_cast<VirtualGPU&>(vDev_); }
|
||||
|
||||
//! Returns the GPU device object
|
||||
const Device& dev() const { return static_cast<const Device&>(dev_); };
|
||||
|
||||
inline Memory& gpuMem(device::Memory& mem) const;
|
||||
|
||||
const size_t MinSizeForPinnedTransfer;
|
||||
bool completeOperation_; //!< DMA blit manager must complete operation
|
||||
|
||||
private:
|
||||
|
||||
//! Disable copy constructor
|
||||
DmaBlitManager(const DmaBlitManager&);
|
||||
|
||||
//! Disable operator=
|
||||
DmaBlitManager& operator=(const DmaBlitManager&);
|
||||
|
||||
//! Reads video memory, using a staged buffer
|
||||
bool readMemoryStaged(
|
||||
Resource& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
Resource** xferBuf, //!< Staged buffer for read
|
||||
size_t origin, //!< Original offset in the source memory
|
||||
size_t& offset, //!< Offset for the current copy pointer
|
||||
size_t& totalSize, //!< Total size for copy region
|
||||
size_t xferSize //!< Transfer size
|
||||
) const;
|
||||
|
||||
//! Write into video memory, using a staged buffer
|
||||
bool writeMemoryStaged(
|
||||
const void* srcHost, //!< Source host memory
|
||||
Resource& dstMemory, //!< Destination memory object
|
||||
Resource& xferBuf, //!< Staged buffer for write
|
||||
size_t origin, //!< Original offset in the destination memory
|
||||
size_t& offset, //!< Offset for the current copy pointer
|
||||
size_t& totalSize, //!< Total size for the copy region
|
||||
size_t xferSize //!< Transfer size
|
||||
) const;
|
||||
};
|
||||
|
||||
//! Kernel Blit Manager
|
||||
class KernelBlitManager : public DmaBlitManager
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
BlitCopyImage = 0,
|
||||
BlitCopyImage1DA,
|
||||
BlitCopyImageToBuffer,
|
||||
BlitCopyBufferToImage,
|
||||
BlitCopyBufferRect,
|
||||
BlitCopyBufferRectAligned,
|
||||
BlitCopyBuffer,
|
||||
BlitCopyBufferAligned,
|
||||
FillBuffer,
|
||||
FillImage,
|
||||
Scheduler,
|
||||
BlitTotal
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
KernelBlitManager(
|
||||
VirtualGPU& gpu, //!< Virtual GPU to be used for blits
|
||||
Setup setup = Setup() //!< Specifies HW accelerated blits
|
||||
);
|
||||
|
||||
//! Destructor
|
||||
virtual ~KernelBlitManager();
|
||||
|
||||
//! Creates DmaBlitManager object
|
||||
virtual bool create(amd::Device& device);
|
||||
|
||||
//! Copies a buffer object to another buffer object
|
||||
virtual bool copyBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& srcRectIn, //!< Source rectangle
|
||||
const amd::BufferRect& dstRectIn, //!< Destination rectangle
|
||||
const amd::Coord3D& sizeIn, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to system memory
|
||||
virtual bool readBufferRect(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destinaiton host memory
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBuffer(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to a buffer object
|
||||
virtual bool writeBufferRect(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::BufferRect& hostRect, //!< Destination rectangle
|
||||
const amd::BufferRect& bufRect, //!< Source rectangle
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
virtual bool copyBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
virtual bool copyBufferToImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies an image object to a buffer object
|
||||
virtual bool copyImageToBuffer(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies an image object to another image object
|
||||
virtual bool copyImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies an image object to system memory
|
||||
virtual bool readImage(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
void* dstHost, //!< Destination host memory
|
||||
const amd::Coord3D& origin, //!< Source origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Copies system memory to an image object
|
||||
virtual bool writeImage(
|
||||
const void* srcHost, //!< Source host memory
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
size_t rowPitch, //!< Row pitch for host memory
|
||||
size_t slicePitch, //!< Slice pitch for host memory
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Fills a buffer memory with a pattern data
|
||||
virtual bool fillBuffer(
|
||||
device::Memory& memory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
size_t patternSize, //!< Pattern size
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Fills an image memory with a pattern data
|
||||
virtual bool fillImage(
|
||||
device::Memory& dstMemory, //!< Memory object to fill with pattern
|
||||
const void* pattern, //!< Pattern data
|
||||
const amd::Coord3D& origin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false //!< Entire buffer will be updated
|
||||
) const;
|
||||
|
||||
//! Fills an image memory with a pattern data
|
||||
virtual bool runScheduler(
|
||||
device::Memory& vqueue, //!< Memory object for virtual queue
|
||||
device::Memory& params, //!< Extra arguments for the scheduler
|
||||
uint paramIdx, //!< Parameter index
|
||||
uint numSlots //!< Number of slots in the queue
|
||||
) const;
|
||||
|
||||
private:
|
||||
static const size_t MaxXferBuffers = 2;
|
||||
|
||||
//! Copies a buffer object to an image object
|
||||
bool copyBufferToImageKernel(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Copies an image object to a buffer object
|
||||
bool copyImageToBufferKernel(
|
||||
device::Memory& srcMemory, //!< Source memory object
|
||||
device::Memory& dstMemory, //!< Destination memory object
|
||||
const amd::Coord3D& srcOrigin, //!< Source origin
|
||||
const amd::Coord3D& dstOrigin, //!< Destination origin
|
||||
const amd::Coord3D& size, //!< Size of the copy region
|
||||
bool entire = false, //!< Entire buffer will be updated
|
||||
size_t rowPitch = 0, //!< Pitch for buffer
|
||||
size_t slicePitch = 0 //!< Slice for buffer
|
||||
) const;
|
||||
|
||||
//! Creates a program for all blit operations
|
||||
bool createProgram(
|
||||
Device& device //!< Device object
|
||||
);
|
||||
|
||||
//! Pins host memory for GPU access
|
||||
amd::Memory* pinHostMemory(
|
||||
const void* hostMem, //!< Host memory pointer
|
||||
size_t pinSize, //!< Host memory size
|
||||
size_t& partial //!< Extra offset for memory alignment
|
||||
) const;
|
||||
|
||||
//! Creates a view memory object
|
||||
Memory* createView(
|
||||
const Memory& parent, //!< Parent memory object
|
||||
const CalFormat& format //!< The new format for a view
|
||||
) const;
|
||||
|
||||
//! Disable copy constructor
|
||||
KernelBlitManager(const KernelBlitManager&);
|
||||
|
||||
//! Disable operator=
|
||||
KernelBlitManager& operator=(const KernelBlitManager&);
|
||||
|
||||
amd::Program* program_; //!< GPU program obejct
|
||||
amd::Kernel* kernels_[BlitTotal]; //!< GPU kernels for blit
|
||||
amd::Context* context_; //!< A dummy context
|
||||
amd::Memory* constantBuffer_; //!< An internal CB for blits
|
||||
amd::Memory* xferBuffers_[MaxXferBuffers]; //!< Transfer buffers for images
|
||||
size_t xferBufferSize_; //!< Transfer buffer size
|
||||
amd::Monitor* lockXferOps_; //!< Lock transfer operation
|
||||
};
|
||||
|
||||
static const char* BlitName[KernelBlitManager::BlitTotal] = {
|
||||
"copyImage",
|
||||
"copyImage1DA",
|
||||
"copyImageToBuffer",
|
||||
"copyBufferToImage",
|
||||
"copyBufferRect",
|
||||
"copyBufferRectAligned",
|
||||
"copyBuffer",
|
||||
"copyBufferAligned",
|
||||
"fillBuffer",
|
||||
"fillImage",
|
||||
"scheduler",
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUBLIT_HPP_*/
|
||||
@@ -0,0 +1,450 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include "device/gpu/gpuprogram.hpp"
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
#include "utils/options.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
//CLC_IN_PROCESS_CHANGE
|
||||
extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typeInfo = NULL);
|
||||
|
||||
namespace gpu {
|
||||
|
||||
static int programsCount = 0;
|
||||
|
||||
bool
|
||||
NullProgram::compileImpl(const std::string& src,
|
||||
const std::vector<const std::string*>& headers,
|
||||
const char** headerIncludeNames,
|
||||
amd::option::Options* options)
|
||||
{
|
||||
std::string sourceCode = src;
|
||||
|
||||
if (dev().settings().debugFlags_ & Settings::CheckForILSource) {
|
||||
size_t inc = sourceCode.find("il_cs_", 0);
|
||||
if (inc != std::string::npos) {
|
||||
// CL program is an IL program
|
||||
ilProgram_ = sourceCode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string tempFolder = amd::Os::getTempPath();
|
||||
std::string tempFileName = amd::Os::getTempFileName();
|
||||
|
||||
if (dev().settings().debugFlags_ & Settings::StubCLPrograms) {
|
||||
std::stringstream fileName;
|
||||
std::fstream stubRead;
|
||||
// Dump the IL function
|
||||
fileName << "program_" << programsCount++ << ".cl";
|
||||
stubRead.open(fileName.str().c_str(), (std::fstream::in | std::fstream::binary));
|
||||
// Check if we have OpenCL program
|
||||
if (stubRead.is_open()) {
|
||||
// Find the stream size
|
||||
stubRead.seekg(0, std::fstream::end);
|
||||
size_t size = stubRead.tellg();
|
||||
stubRead.seekg(0, std::ios::beg);
|
||||
|
||||
char* data = new char[size];
|
||||
stubRead.read(data, size);
|
||||
stubRead.close();
|
||||
|
||||
sourceCode.assign(data, size);
|
||||
delete[] data;
|
||||
}
|
||||
else {
|
||||
std::fstream stubWrite;
|
||||
stubWrite.open(fileName.str().c_str(),
|
||||
(std::fstream::out | std::fstream::binary));
|
||||
stubWrite << sourceCode;
|
||||
stubWrite.close();
|
||||
}
|
||||
}
|
||||
|
||||
std::fstream f;
|
||||
std::vector<std::string> headerFileNames(headers.size());
|
||||
std::vector<std::string> newDirs;
|
||||
for (size_t i = 0; i < headers.size(); ++i) {
|
||||
std::string headerPath = tempFolder;
|
||||
std::string headerIncludeName(headerIncludeNames[i]);
|
||||
// replace / in path with current os's file separator
|
||||
if ( amd::Os::fileSeparator() != '/') {
|
||||
for (std::string::iterator it = headerIncludeName.begin(),
|
||||
end = headerIncludeName.end();
|
||||
it != end;
|
||||
++it) {
|
||||
if (*it == '/') *it = amd::Os::fileSeparator();
|
||||
}
|
||||
}
|
||||
size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
|
||||
if (pos != std::string::npos) {
|
||||
headerPath += amd::Os::fileSeparator();
|
||||
headerPath += headerIncludeName.substr(0, pos);
|
||||
headerIncludeName = headerIncludeName.substr(pos+1);
|
||||
}
|
||||
if (!amd::Os::pathExists(headerPath)) {
|
||||
bool ret = amd::Os::createPath(headerPath);
|
||||
assert(ret && "failed creating path!");
|
||||
newDirs.push_back(headerPath);
|
||||
}
|
||||
std::string headerFullName
|
||||
= headerPath + amd::Os::fileSeparator() + headerIncludeName;
|
||||
headerFileNames[i] = headerFullName;
|
||||
f.open(headerFullName.c_str(), std::fstream::out);
|
||||
assert(!f.fail() && "failed creating header file!");
|
||||
f.write(headers[i]->c_str(), headers[i]->length());
|
||||
f.close();
|
||||
}
|
||||
|
||||
acl_error err;
|
||||
const aclTargetInfo& targInfo = info();
|
||||
|
||||
aclBinaryOptions binOpts = {0};
|
||||
binOpts.struct_size = sizeof(binOpts);
|
||||
binOpts.elfclass = targInfo.arch_id == aclAMDIL64 ? ELFCLASS64 : ELFCLASS32;
|
||||
binOpts.bitness = ELFDATA2LSB;
|
||||
binOpts.alloc = &::malloc;
|
||||
binOpts.dealloc = &::free;
|
||||
|
||||
aclBinary* bin
|
||||
= aclBinaryInit(sizeof(aclBinary), &targInfo, &binOpts, &err);
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclBinaryInit failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ACL_SUCCESS != aclInsertSection(dev().compiler(), bin,
|
||||
sourceCode.c_str(), sourceCode.size(), aclSOURCE)) {
|
||||
LogWarning("aclInsertSection failed");
|
||||
aclBinaryFini(bin);
|
||||
return false;
|
||||
}
|
||||
|
||||
// temporary solution to synchronize buildNo between runtime and complib
|
||||
// until we move runtime inside complib
|
||||
((amd::option::Options*)bin->options)->setBuildNo(options->getBuildNo());
|
||||
|
||||
std::stringstream opts;
|
||||
std::string token;
|
||||
opts << options->origOptionStr.c_str();
|
||||
|
||||
if (options->origOptionStr.find("-cl-std=CL") == std::string::npos) {
|
||||
switch(dev().settings().oclVersion_) {
|
||||
case OpenCL10: opts << " -cl-std=CL1.0"; break;
|
||||
case OpenCL11: opts << " -cl-std=CL1.1"; break;
|
||||
case OpenCL20: default:
|
||||
case OpenCL12: opts << " -cl-std=CL1.2"; break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should we prefix everything with -Wf,?
|
||||
std::istringstream iss(options->clcOptions);
|
||||
while (getline(iss, token, ' ')) {
|
||||
if (!token.empty()) {
|
||||
// Check if this is a -D option
|
||||
if (token.compare("-D") == 0) {
|
||||
// It is, skip payload
|
||||
getline(iss, token, ' ');
|
||||
continue;
|
||||
}
|
||||
opts << " -Wf," << token;
|
||||
}
|
||||
}
|
||||
|
||||
if (!headers.empty()) {
|
||||
opts << " -I" << tempFolder;
|
||||
}
|
||||
|
||||
if (!dev().settings().imageSupport_) {
|
||||
opts << " -fno-image-support";
|
||||
}
|
||||
|
||||
if (dev().settings().reportFMAF_) {
|
||||
opts << " -mfast-fmaf";
|
||||
}
|
||||
|
||||
if (dev().settings().reportFMA_) {
|
||||
opts << " -mfast-fma";
|
||||
}
|
||||
|
||||
iss.clear();
|
||||
iss.str(device().info().extensions_);
|
||||
while (getline(iss, token, ' ')) {
|
||||
if (!token.empty()) {
|
||||
opts << " -D" << token << "=1";
|
||||
}
|
||||
}
|
||||
|
||||
std::string newOpt = opts.str();
|
||||
size_t pos = newOpt.find("-fno-bin-llvmir");
|
||||
while (pos != std::string::npos) {
|
||||
newOpt.erase(pos, 15);
|
||||
pos = newOpt.find("-fno-bin-llvmir");
|
||||
}
|
||||
|
||||
err = aclCompile(dev().compiler(), bin, newOpt.c_str(),
|
||||
ACL_TYPE_OPENCL, ACL_TYPE_LLVMIR_BINARY, NULL);
|
||||
|
||||
buildLog_ += aclGetCompilerLog(dev().compiler());
|
||||
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclCompile failed");
|
||||
aclBinaryFini(bin);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
const void* ir = aclExtractSection(dev().compiler(), bin,
|
||||
&len, aclLLVMIR, &err);
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclExtractSection failed");
|
||||
aclBinaryFini(bin);
|
||||
return false;
|
||||
}
|
||||
|
||||
llvmBinary_.assign(reinterpret_cast<const char*>(ir), len);
|
||||
llvmBinaryIsSpir_ = false;
|
||||
aclBinaryFini(bin);
|
||||
|
||||
for (size_t i = 0; i < headerFileNames.size(); ++i) {
|
||||
amd::Os::unlink(headerFileNames[i].c_str());
|
||||
}
|
||||
for (size_t i = 0; i < newDirs.size(); ++i) {
|
||||
amd::Os::removePath(newDirs[i]);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
amd::Os::unlink(tempFileName);
|
||||
#endif
|
||||
|
||||
if (clBinary()->saveSOURCE()) {
|
||||
clBinary()->elfOut()->addSection(
|
||||
amd::OclElf::SOURCE, sourceCode.data(), sourceCode.size());
|
||||
}
|
||||
if (clBinary()->saveLLVMIR()) {
|
||||
clBinary()->elfOut()->addSection(
|
||||
amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
|
||||
// store the original compile options
|
||||
clBinary()->storeCompileOptions(compileOptions_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
NullProgram::compileBinaryToIL(amd::option::Options* options)
|
||||
{
|
||||
acl_error err;
|
||||
const aclTargetInfo& targInfo = info();
|
||||
|
||||
aclBinaryOptions binOpts = {0};
|
||||
binOpts.struct_size = sizeof(binOpts);
|
||||
binOpts.elfclass = targInfo.arch_id == aclAMDIL64 ? ELFCLASS64 : ELFCLASS32;
|
||||
binOpts.bitness = ELFDATA2LSB;
|
||||
binOpts.alloc = &::malloc;
|
||||
binOpts.dealloc = &::free;
|
||||
|
||||
aclBinary* bin
|
||||
= aclBinaryInit(sizeof(aclBinary), &targInfo, &binOpts, &err);
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclBinaryInit failed");
|
||||
return CL_BUILD_PROGRAM_FAILURE;
|
||||
}
|
||||
bool spirFlag = std::string::npos != options->clcOptions.find("--spir")
|
||||
|| llvmBinaryIsSpir_;
|
||||
if (ACL_SUCCESS != aclInsertSection(dev().compiler(), bin,
|
||||
llvmBinary_.data(), llvmBinary_.size(),
|
||||
spirFlag ? aclSPIR : aclLLVMIR)) {
|
||||
LogWarning("aclInsertSection failed");
|
||||
aclBinaryFini(bin);
|
||||
return CL_BUILD_PROGRAM_FAILURE;
|
||||
}
|
||||
|
||||
// pass kernel argument alignment info to compiler lib through option str
|
||||
std::string optionStr = options->origOptionStr;
|
||||
if (options->origOptionStr.find("kernel-arg-alignment")
|
||||
== std::string::npos) {
|
||||
char s[256];
|
||||
sprintf(s, " -Wb,-kernel-arg-alignment=%d",
|
||||
dev().info().memBaseAddrAlign_ / 8);
|
||||
optionStr += s;
|
||||
}
|
||||
|
||||
// temporary solution to synchronize buildNo between runtime and complib
|
||||
// until we move runtime inside complib
|
||||
((amd::option::Options*)bin->options)->setBuildNo(options->getBuildNo());
|
||||
|
||||
aclType type = ACL_TYPE_CG ;
|
||||
// If option bin-bif30 is set, generate BIF 3.0 binary
|
||||
if (options->oVariables->BinBIF30) {
|
||||
type = ACL_TYPE_ISA;
|
||||
}
|
||||
err = aclCompile(dev().compiler(), bin, optionStr.c_str(),
|
||||
spirFlag ? ACL_TYPE_SPIR_BINARY : ACL_TYPE_LLVMIR_BINARY,
|
||||
type, NULL);
|
||||
|
||||
buildLog_ += aclGetCompilerLog(dev().compiler());
|
||||
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclCompile failed");
|
||||
aclBinaryFini(bin);
|
||||
return CL_BUILD_PROGRAM_FAILURE;
|
||||
}
|
||||
|
||||
if (options->oVariables->BinBIF30) {
|
||||
if (!createBIFBinary(bin)) {
|
||||
aclBinaryFini(bin);
|
||||
return CL_BUILD_PROGRAM_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
const void* amdil = aclExtractSection(dev().compiler(), bin,
|
||||
&len, aclCODEGEN, &err);
|
||||
if (err != ACL_SUCCESS) {
|
||||
LogWarning("aclExtractSection failed");
|
||||
aclBinaryFini(bin);
|
||||
return CL_BUILD_PROGRAM_FAILURE;
|
||||
}
|
||||
|
||||
ilProgram_.assign(reinterpret_cast<const char*>(amdil), len);
|
||||
aclBinaryFini(bin);
|
||||
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
HSAILProgram::compileImpl(
|
||||
const std::string& sourceCode,
|
||||
const std::vector<const std::string*>& headers,
|
||||
const char** headerIncludeNames,
|
||||
amd::option::Options* options)
|
||||
{
|
||||
acl_error errorCode;
|
||||
aclTargetInfo target;
|
||||
|
||||
std::string arch = "hsail";
|
||||
if (dev().settings().use64BitPtr_) {
|
||||
arch += "-64";
|
||||
}
|
||||
target = aclGetTargetInfo(arch.c_str(),
|
||||
dev().info().name_, &errorCode);
|
||||
|
||||
// end if asic info is ready
|
||||
// We dump the source code for each program (param: headers)
|
||||
// into their filenames (headerIncludeNames) into the TEMP
|
||||
// folder specific to the OS and add the include path while
|
||||
// compiling
|
||||
|
||||
// Find the temp folder for the OS
|
||||
std::string tempFolder = amd::Os::getTempPath();
|
||||
std::string tempFileName = amd::Os::getTempFileName();
|
||||
|
||||
// Iterate through each source code and dump it into tmp
|
||||
std::fstream f;
|
||||
std::vector<std::string> headerFileNames(headers.size());
|
||||
std::vector<std::string> newDirs;
|
||||
for (size_t i = 0; i < headers.size(); ++i) {
|
||||
std::string headerPath = tempFolder;
|
||||
std::string headerIncludeName(headerIncludeNames[i]);
|
||||
// replace / in path with current os's file separator
|
||||
if (amd::Os::fileSeparator() != '/') {
|
||||
for (std::string::iterator it = headerIncludeName.begin(),
|
||||
end = headerIncludeName.end(); it != end; ++it) {
|
||||
if (*it == '/') *it = amd::Os::fileSeparator();
|
||||
}
|
||||
}
|
||||
size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
|
||||
if (pos != std::string::npos) {
|
||||
headerPath += amd::Os::fileSeparator();
|
||||
headerPath += headerIncludeName.substr(0, pos);
|
||||
headerIncludeName = headerIncludeName.substr(pos+1);
|
||||
}
|
||||
if (!amd::Os::pathExists(headerPath)) {
|
||||
bool ret = amd::Os::createPath(headerPath);
|
||||
assert(ret && "failed creating path!");
|
||||
newDirs.push_back(headerPath);
|
||||
}
|
||||
std::string headerFullName =
|
||||
headerPath + amd::Os::fileSeparator() + headerIncludeName;
|
||||
headerFileNames[i] = headerFullName;
|
||||
f.open(headerFullName.c_str(), std::fstream::out);
|
||||
// Should we allow asserts
|
||||
assert(!f.fail() && "failed creating header file!");
|
||||
f.write(headers[i]->c_str(), headers[i]->length());
|
||||
f.close();
|
||||
}
|
||||
|
||||
// Create Binary
|
||||
binaryElf_ = aclBinaryInit(sizeof(aclBinary),
|
||||
&target, &binOpts_, &errorCode);
|
||||
if (errorCode != ACL_SUCCESS) {
|
||||
buildLog_ += "Error: aclBinary init failure\n";
|
||||
LogWarning("aclBinaryInit failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Insert opencl into binary
|
||||
errorCode = aclInsertSection(dev().hsaCompiler(), binaryElf_,
|
||||
sourceCode.c_str(), strlen(sourceCode.c_str()), aclSOURCE);
|
||||
if (errorCode != ACL_SUCCESS) {
|
||||
buildLog_ += "Error: Inserting openCl Source to binary\n";
|
||||
}
|
||||
|
||||
// Set the options for the compiler
|
||||
// Set the include path for the temp folder that contains the includes
|
||||
if (!headers.empty()) {
|
||||
compileOptions_.append(" -I");
|
||||
compileOptions_.append(tempFolder);
|
||||
}
|
||||
|
||||
//Add only for CL2.0 and above
|
||||
if (options->oVariables->CLStd[2] >= '2') {
|
||||
std::stringstream opts;
|
||||
opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
|
||||
<< device().info().maxGlobalVariableSize_;
|
||||
compileOptions_.append(opts.str());
|
||||
}
|
||||
|
||||
#if !defined(_LP64)
|
||||
if (options->origOptionStr.find("-cl-std=CL2.0") != std::string::npos && !dev().settings().force32BitOcl20_) {
|
||||
errorCode = ACL_UNSUPPORTED;
|
||||
LogWarning("aclCompile failed");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Compile source to IR
|
||||
compileOptions_.append(hsailOptions());
|
||||
errorCode = aclCompile(dev().hsaCompiler(), binaryElf_, compileOptions_.c_str(),
|
||||
ACL_TYPE_OPENCL, ACL_TYPE_LLVMIR_BINARY, NULL);
|
||||
buildLog_ += aclGetCompilerLog(dev().hsaCompiler());
|
||||
if (errorCode != ACL_SUCCESS) {
|
||||
LogWarning("aclCompile failed");
|
||||
buildLog_ += "Error: Compiling CL to IR\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the binary in the interface class
|
||||
size_t size = 0;
|
||||
void* mem = NULL;
|
||||
aclWriteToMem(binaryElf_, &mem, &size);
|
||||
setBinary(static_cast<char*>(mem), size);
|
||||
|
||||
// Save the binary inside the program
|
||||
// The FSAILProgram will be responsible to free it during destruction
|
||||
rawBinary_ = mem;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gpuconstbuf.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include "device/gpu/gpusettings.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
ConstBuffer::ConstBuffer(
|
||||
VirtualGPU& gpu,
|
||||
size_t size)
|
||||
: Resource(const_cast<gpu::Device&>(gpu.dev()), size, CM_SURF_FMT_RGBA32F)
|
||||
, gpu_(gpu)
|
||||
, size_(size * VectorSize)
|
||||
, wrtOffset_(0)
|
||||
, lastWrtSize_(0)
|
||||
, wrtAddress_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
ConstBuffer::~ConstBuffer()
|
||||
{
|
||||
if (wrtAddress_ != NULL) {
|
||||
unmap(&gpu_);
|
||||
}
|
||||
|
||||
amd::AlignedMemory::deallocate(sysMemCopy_);
|
||||
}
|
||||
|
||||
bool
|
||||
ConstBuffer::create()
|
||||
{
|
||||
// Create sysmem copy for the constant buffer
|
||||
sysMemCopy_ = reinterpret_cast<address>(amd::AlignedMemory::allocate(size_, 256));
|
||||
if (sysMemCopy_ == NULL) {
|
||||
LogPrintfError("We couldn't allocate sysmem copy for constant buffer,\
|
||||
size(%d)!", size_);
|
||||
return false;
|
||||
}
|
||||
memset(sysMemCopy_, 0, size_);
|
||||
|
||||
if (!Resource::create(Resource::RemoteUSWC)) {
|
||||
LogPrintfError("We couldn't create HW constant buffer, size(%d)!", size_);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Constant buffer warm-up
|
||||
warmUpRenames(gpu_);
|
||||
|
||||
wrtAddress_ = map(&gpu_, Resource::Discard);
|
||||
if (wrtAddress_ == NULL) {
|
||||
LogPrintfError("We couldn't map HW constant buffer, size(%d)!", size_);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ConstBuffer::uploadDataToHw(size_t size)
|
||||
{
|
||||
static const size_t HwCbAlignment = 256;
|
||||
|
||||
// Align copy size on the vector's boundary
|
||||
size_t count = amd::alignUp(size, VectorSize);
|
||||
wrtOffset_ += lastWrtSize_;
|
||||
|
||||
// Check if CB has enough space for copy
|
||||
if ((wrtOffset_ + count) > size_) {
|
||||
if (wrtAddress_ != NULL) {
|
||||
unmap(&gpu_);
|
||||
}
|
||||
wrtAddress_ = map(&gpu_, Resource::Discard);
|
||||
wrtOffset_ = 0;
|
||||
lastWrtSize_ = 0;
|
||||
}
|
||||
|
||||
// Update memory with new CB data
|
||||
memcpy((reinterpret_cast<char*>(wrtAddress_) + wrtOffset_), sysMemCopy_, count);
|
||||
|
||||
// Adjust the size by the HW CB buffer alignment
|
||||
lastWrtSize_ = amd::alignUp(size, HwCbAlignment);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUCONSTBUF_HPP_
|
||||
#define GPUCONSTBUF_HPP_
|
||||
|
||||
#include "device/gpu/gpuresource.hpp"
|
||||
|
||||
//! \namespace gpu GPU Resource Implementation
|
||||
namespace gpu {
|
||||
|
||||
//! Cconstant buffer
|
||||
class ConstBuffer : public Resource
|
||||
{
|
||||
public:
|
||||
//! Vector size of the constant buffer
|
||||
static const size_t VectorSize = 16;
|
||||
|
||||
//! Constructor for the ConstBuffer class
|
||||
ConstBuffer(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
size_t size //!< size of the constant buffer in vectors
|
||||
);
|
||||
|
||||
//! Destructor for the ConstBuffer class
|
||||
~ConstBuffer();
|
||||
|
||||
//! Creates the real HW constant buffer
|
||||
bool create();
|
||||
|
||||
/*! \brief Uploads current constant buffer data from sysMemCopy_ to HW
|
||||
*
|
||||
* \return True if the data upload was succesful
|
||||
*/
|
||||
bool uploadDataToHw(
|
||||
size_t size //!< real data size for upload
|
||||
);
|
||||
|
||||
//! Returns a pointer to the system memory copy for CB
|
||||
address sysMemCopy() const { return sysMemCopy_; }
|
||||
|
||||
//! Returns CB size
|
||||
size_t size() const { return size_; }
|
||||
|
||||
//! Returns current write offset for the constant buffer
|
||||
size_t wrtOffset() const { return wrtOffset_; }
|
||||
|
||||
//! Returns last write size for the constant buffer
|
||||
size_t lastWrtSize() const { return lastWrtSize_; }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
ConstBuffer(const ConstBuffer&);
|
||||
|
||||
//! Disable operator=
|
||||
ConstBuffer& operator=(const ConstBuffer&);
|
||||
|
||||
VirtualGPU& gpu_; //!< Virtual GPU object
|
||||
address sysMemCopy_; //!< System memory copy
|
||||
size_t size_; //!< Constant buffer size
|
||||
size_t wrtOffset_; //!< Current write offset
|
||||
size_t lastWrtSize_; //!< Last write size
|
||||
void* wrtAddress_; //!< Write address in CB
|
||||
};
|
||||
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUCONSTBUF_HPP_*/
|
||||
@@ -0,0 +1,87 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpucounters.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
CalCounterReference::~CalCounterReference() {
|
||||
// The counter object is always associated with a particular queue,
|
||||
// so we have to lock just this queue
|
||||
amd::ScopedLock lock(gpu_.execution());
|
||||
|
||||
if (0 != counter_) {
|
||||
gpu().destroyCounter(gslCounter());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CalCounterReference::growResultArray(uint index) {
|
||||
if (results_ != NULL) {
|
||||
delete [] results_;
|
||||
}
|
||||
results_ = new uint64_t [index + 1];
|
||||
if (results_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PerfCounter::~PerfCounter()
|
||||
{
|
||||
if (calRef_ == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Release the counter reference object
|
||||
calRef_->release();
|
||||
}
|
||||
|
||||
bool
|
||||
PerfCounter::create(
|
||||
CalCounterReference* calRef)
|
||||
{
|
||||
assert(&gpu() == &calRef->gpu());
|
||||
|
||||
calRef_ = calRef;
|
||||
counter_ = calRef->gslCounter();
|
||||
index_ = calRef->retain() - 2;
|
||||
calRef->growResultArray(index_);
|
||||
|
||||
// Initialize the counter
|
||||
gpu().configPerformanceCounter(gslCounter(),
|
||||
info()->blockIndex_, info()->counterIndex_, info()->eventIndex_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PerfCounter::getInfo(uint64_t infoType) const
|
||||
{
|
||||
switch (infoType) {
|
||||
case CL_PERFCOUNTER_GPU_BLOCK_INDEX: {
|
||||
// Return the GPU block index
|
||||
return info()->blockIndex_;
|
||||
}
|
||||
case CL_PERFCOUNTER_GPU_COUNTER_INDEX: {
|
||||
// Return the GPU counter index
|
||||
return info()->counterIndex_;
|
||||
}
|
||||
case CL_PERFCOUNTER_GPU_EVENT_INDEX: {
|
||||
// Return the GPU event index
|
||||
return info()->eventIndex_;
|
||||
}
|
||||
case CL_PERFCOUNTER_DATA: {
|
||||
gpu().getCounter(reinterpret_cast<uint64*>(calRef_->results()), gslCounter());
|
||||
return calRef_->results()[index_];
|
||||
}
|
||||
default:
|
||||
LogError("Wrong PerfCounter::getInfo parameter");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUCOUNTERS_HPP_
|
||||
#define GPUCOUNTERS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class VirtualGPU;
|
||||
|
||||
class CalCounterReference : public amd::ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
CalCounterReference(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
gslQueryObject gslCounter)
|
||||
: gpu_(gpu)
|
||||
, counter_(gslCounter)
|
||||
, results_(NULL) {}
|
||||
|
||||
//! Get CAL counter
|
||||
gslQueryObject gslCounter() const { return counter_; }
|
||||
|
||||
//! Returns the virtual GPU device
|
||||
const VirtualGPU& gpu() const { return gpu_; }
|
||||
|
||||
//! Increases the results array for this CAL counter(container)
|
||||
bool growResultArray(
|
||||
uint maxIndex //!< the maximum HW counter index in the CAL counter
|
||||
);
|
||||
|
||||
//! Returns the CAL counter results
|
||||
uint64_t* results() const { return results_; }
|
||||
|
||||
protected:
|
||||
//! Default destructor
|
||||
~CalCounterReference();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
CalCounterReference(const CalCounterReference&);
|
||||
|
||||
//! Disable operator=
|
||||
CalCounterReference& operator=(const CalCounterReference&);
|
||||
|
||||
VirtualGPU& gpu_; //!< The virtual GPU device object
|
||||
gslQueryObject counter_; //!< GSL object counter
|
||||
uint64_t* results_; //!< CAL counter results
|
||||
};
|
||||
|
||||
//! Performance counter implementation on GPU
|
||||
class PerfCounter : public device::PerfCounter
|
||||
{
|
||||
public:
|
||||
//! The performance counter info
|
||||
struct Info : public amd::EmbeddedObject
|
||||
{
|
||||
uint blockIndex_; //!< Index of the block to configure
|
||||
uint counterIndex_; //!< Index of the hardware counter
|
||||
uint eventIndex_; //!< Event you wish to count with the counter
|
||||
};
|
||||
|
||||
//! The PerfCounter flags
|
||||
enum Flags
|
||||
{
|
||||
BeginIssued = 0x00000001,
|
||||
EndIssued = 0x00000002,
|
||||
ResultReady = 0x00000004
|
||||
};
|
||||
|
||||
//! Constructor for the GPU PerfCounter object
|
||||
PerfCounter(
|
||||
const Device& device, //!< A GPU device object
|
||||
const VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
cl_uint blockIndex, //!< HW block index
|
||||
cl_uint counterIndex, //!< Counter index within the block
|
||||
cl_uint eventIndex) //!< Event index for profiling
|
||||
: gpuDevice_(device)
|
||||
, gpu_(gpu)
|
||||
, calRef_(NULL)
|
||||
, flags_(0)
|
||||
, counter_(0)
|
||||
, index_(0)
|
||||
{
|
||||
info_.blockIndex_ = blockIndex;
|
||||
info_.counterIndex_ = counterIndex;
|
||||
info_.eventIndex_ = eventIndex;
|
||||
}
|
||||
|
||||
//! Destructor for the GPU PerfCounter object
|
||||
virtual ~PerfCounter();
|
||||
|
||||
//! Creates the current object
|
||||
bool create(
|
||||
CalCounterReference* calRef //!< Reference counter
|
||||
);
|
||||
|
||||
//! Returns the specific information about the counter
|
||||
uint64_t getInfo(
|
||||
uint64_t infoType //!< The type of returned information
|
||||
) const;
|
||||
|
||||
//! Returns the GPU device, associated with the current object
|
||||
const Device& dev() const { return gpuDevice_; }
|
||||
|
||||
//! Returns the virtual GPU device
|
||||
const VirtualGPU& gpu() const { return gpu_; }
|
||||
|
||||
//! Returns the CAL performance counter descriptor
|
||||
const Info* info() const { return &info_; }
|
||||
|
||||
//! Returns the Info structure for performance counter
|
||||
gslQueryObject gslCounter() const { return counter_; }
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
PerfCounter(const PerfCounter&);
|
||||
|
||||
//! Disable default operator=
|
||||
PerfCounter& operator=(const PerfCounter&);
|
||||
|
||||
const Device& gpuDevice_; //!< The backend device
|
||||
const VirtualGPU& gpu_; //!< The virtual GPU device object
|
||||
|
||||
CalCounterReference* calRef_; //!< Reference counter
|
||||
uint flags_; //!< The perfcounter object state
|
||||
Info info_; //!< The info structure for perfcounter
|
||||
gslQueryObject counter_; //!< GSL counter object
|
||||
uint index_; //!< Counter index in the CAL container
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPUCOUNTERS_HPP_
|
||||
|
||||
@@ -0,0 +1,450 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUDEFS_HPP_
|
||||
#define GPUDEFS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
|
||||
#include "cal.h"
|
||||
#include "calcl.h"
|
||||
#include "gsl_types.h"
|
||||
#include "gsl_config.h"
|
||||
#include "gsl_vid_if.h"
|
||||
#include "gsl_ctx.h"
|
||||
#include "backend.h"
|
||||
#include "GSLDevice.h"
|
||||
#include "GSLContext.h"
|
||||
|
||||
extern bool getFuncInfoFromImage(CALimage image, CALfuncInfo *pFuncInfo);
|
||||
|
||||
/*! \addtogroup GPU
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
|
||||
namespace gpu {
|
||||
|
||||
//! Maximum number of the supported global atomic counters
|
||||
const static uint MaxAtomicCounters = 8;
|
||||
//! Maximum number of the supported samplers
|
||||
const static uint MaxSamplers = 16;
|
||||
//! Maximum number of supported read images
|
||||
const static uint MaxReadImage = 128;
|
||||
//! Maximum number of supported write images
|
||||
const static uint MaxWriteImage = 8;
|
||||
//! Maximum number of supported read/write images for OCL20
|
||||
const static uint MaxReadWriteImage = 64;
|
||||
//! Maximum number of supported constant arguments
|
||||
const static uint MaxConstArguments = 8;
|
||||
//! Maximum number of supported kernel UAV arguments
|
||||
const static uint MaxUavArguments = 1024;
|
||||
//! Maximum number of pixels for a 1D image created from a buffer
|
||||
const static size_t MaxImageBufferSize = 65536;
|
||||
//! Maximum number of pixels for a 1D image created from a buffer
|
||||
const static size_t MaxImageArraySize = 2048;
|
||||
|
||||
//! Maximum number of supported constant buffers
|
||||
const static uint MaxConstBuffers = MaxConstArguments + 8;
|
||||
|
||||
//! Maximum number of constant buffers for arguments
|
||||
const static uint MaxConstBuffersArguments = 2;
|
||||
|
||||
//! Define offline CAL implementation
|
||||
const static uint CalOfflineImpl = 0xffffffff;
|
||||
|
||||
//! Alignment restriciton for the pinned memory
|
||||
const static size_t PinnedMemoryAlignment = 4 * Ki;
|
||||
|
||||
//! Reserved address space
|
||||
const static cl_ulong ReservedAdressSpaceSize = static_cast<cl_ulong>(4) * Gi;
|
||||
|
||||
//! Defines all supported ASIC families
|
||||
enum AsicFamilies {
|
||||
Family7xx,
|
||||
Family8xx,
|
||||
FamilyTotal
|
||||
};
|
||||
|
||||
struct AMDDeviceInfo {
|
||||
uint machine_; //!< Machine target ID
|
||||
const char* targetName_; //!< Target name
|
||||
const char* machineTarget_; //!< Machine target
|
||||
uint simdPerCU_; //!< Number of SIMDs per CU
|
||||
uint simdWidth_; //!< Number of workitems processed per SIMD
|
||||
uint simdInstructionWidth_; //!< Number of instructions processed per SIMD
|
||||
uint memChannelBankWidth_; //!< Memory channel bank width
|
||||
uint localMemSizePerCU_; //!< Local memory size per CU
|
||||
uint localMemBanks_; //!< Number of banks of local memory
|
||||
uint gfxipVersion_; //!< The core engine GFXIP version
|
||||
};
|
||||
|
||||
|
||||
static const AMDDeviceInfo DeviceInfo[] = {
|
||||
// Machine targetName machineTarget
|
||||
/* CAL_TARGET_600 */ { ED_ATI_CAL_MACHINE_R600_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_610 */ { ED_ATI_CAL_MACHINE_R610_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_630 */ { ED_ATI_CAL_MACHINE_R630_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_670 */ { ED_ATI_CAL_MACHINE_R670_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_7XX */ { ED_ATI_CAL_MACHINE_R770_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_770 */ { ED_ATI_CAL_MACHINE_R770_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_710 */ { ED_ATI_CAL_MACHINE_R710_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_730 */ { ED_ATI_CAL_MACHINE_R730_ISA, "", "", 0, 0, 0, 0, 0, 0, 0 },
|
||||
/* CAL_TARGET_CYPRESS */ { ED_ATI_CAL_MACHINE_CYPRESS_ISA, "Cypress", "cypress", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_JUNIPER */ { ED_ATI_CAL_MACHINE_JUNIPER_ISA, "Juniper", "juniper", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_REDWOOD */ { ED_ATI_CAL_MACHINE_REDWOOD_ISA, "Redwood", "redwood", 1, 16, 5, 256, 32 * Ki, 16, 400 },
|
||||
/* CAL_TARGET_CEDAR */ { ED_ATI_CAL_MACHINE_CEDAR_ISA, "Cedar", "cedar", 1, 8, 5, 256, 32 * Ki, 16, 400 },
|
||||
/* CAL_TARGET_SUMO */ { ED_ATI_CAL_MACHINE_SUMO_ISA, "WinterPark", "redwood", 1, 16, 5, 256, 32 * Ki, 16, 400 },
|
||||
/* CAL_TARGET_SUPERSUMO*/ { ED_ATI_CAL_MACHINE_SUPERSUMO_ISA, "BeaverCreek", "redwood", 1, 16, 5, 256, 32 * Ki, 16, 400 },
|
||||
/* CAL_TARGET_WRESTLER*/ { ED_ATI_CAL_MACHINE_WRESTLER_ISA, "Loveland", "cedar", 1, 8, 5, 256, 32 * Ki, 16, 400 },
|
||||
/* CAL_TARGET_CAYMAN */ { ED_ATI_CAL_MACHINE_CAYMAN_ISA, "Cayman", "cayman", 1, 16, 4, 256, 32 * Ki, 32, 500 },
|
||||
/* CAL_TARGET_KAUAI */ { ED_ATI_CAL_MACHINE_KAUAI_ISA, "", "", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_BARTS */ { ED_ATI_CAL_MACHINE_BARTS_ISA , "Barts", "barts", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_TURKS */ { ED_ATI_CAL_MACHINE_TURKS_ISA , "Turks", "turks", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_CAICOS */ { ED_ATI_CAL_MACHINE_CAICOS_ISA, "Caicos", "caicos", 1, 16, 5, 256, 32 * Ki, 32, 400 },
|
||||
/* CAL_TARGET_TAHITI */ { ED_ATI_CAL_MACHINE_TAHITI_ISA, "Tahiti", "tahiti", 4, 16, 1, 256, 64 * Ki, 32, 600 },
|
||||
/* CAL_TARGET_PITCAIRN */ { ED_ATI_CAL_MACHINE_PITCAIRN_ISA, "Pitcairn", "pitcairn", 4, 16, 1, 256, 64 * Ki, 32, 600 },
|
||||
/* CAL_TARGET_CAPEVERDE */ { ED_ATI_CAL_MACHINE_CAPEVERDE_ISA, "Capeverde", "capeverde", 4, 16, 1, 256, 64 * Ki, 32, 600 },
|
||||
/* CAL_TARGET_DEVASTATOR */ { ED_ATI_CAL_MACHINE_DEVASTATOR_ISA,"Devastator", "trinity", 1, 16, 4, 256, 32 * Ki, 32, 500 },
|
||||
/* CAL_TARGET_SCRAPPER */ { ED_ATI_CAL_MACHINE_SCRAPPER_ISA, "Scrapper", "trinity", 1, 16, 4, 256, 32 * Ki, 32, 500 },
|
||||
/* CAL_TARGET_OLAND */ { ED_ATI_CAL_MACHINE_OLAND_ISA, "Oland", "oland", 4, 16, 1, 256, 64 * Ki, 32, 600 },
|
||||
/* CAL_TARGET_BONAIRE */ { ED_ATI_CAL_MACHINE_BONAIRE_ISA, "Bonaire", "bonaire", 4, 16, 1, 256, 64 * Ki, 32, 702 },
|
||||
/* CAL_TARGET_SPECTRE */ { ED_ATI_CAL_MACHINE_SPECTRE_ISA, "Spectre", "spectre", 4, 16, 1, 256, 64 * Ki, 32, 701 },
|
||||
/* CAL_TARGET_SPOOKY */ { ED_ATI_CAL_MACHINE_SPOOKY_ISA, "Spooky", "spooky", 4, 16, 1, 256, 64 * Ki, 32, 701 },
|
||||
/* CAL_TARGET_KALINDI */ { ED_ATI_CAL_MACHINE_KALINDI_ISA, "Kalindi", "kalindi", 4, 16, 1, 256, 64 * Ki, 32, 702 },
|
||||
/* CAL_TARGET_HAINAN */ { ED_ATI_CAL_MACHINE_HAINAN_ISA, "Hainan", "hainan", 4, 16, 1, 256, 64 * Ki, 32, 600 },
|
||||
/* CAL_TARGET_HAWAII */ { ED_ATI_CAL_MACHINE_HAWAII_ISA, "Hawaii", "hawaii", 4, 16, 1, 256, 64 * Ki, 32, 702 },
|
||||
/* CAL_TARGET_ICELAND */ { ED_ATI_CAL_MACHINE_ICELAND_ISA, "Iceland", "iceland", 4, 16, 1, 256, 64 * Ki, 32, 800 },
|
||||
/* CAL_TARGET_TONGA */ { ED_ATI_CAL_MACHINE_TONGA_ISA, "Tonga", "tonga", 4, 16, 1, 256, 64 * Ki, 32, 800 },
|
||||
/* CAL_TARGET_MULLINS */ { ED_ATI_CAL_MACHINE_GODAVARI_ISA, "Mullins", "mullins", 4, 16, 1, 256, 64 * Ki, 32, 702 },
|
||||
/* CAL_TARGET_BERMUDA */ { ED_ATI_CAL_MACHINE_BERMUDA_ISA, "", "", 4, 16, 1, 256, 64 * Ki, 32, 800 },
|
||||
/* CAL_TARGET_FIJI */ { ED_ATI_CAL_MACHINE_FIJI_ISA, "", "", 4, 16, 1, 256, 64 * Ki, 32, 800 },
|
||||
/* CAL_TARGET_CARRIZO */ { ED_ATI_CAL_MACHINE_CARRIZO_ISA, "", "", 4, 16, 1, 256, 64 * Ki, 32, 800 },
|
||||
};
|
||||
|
||||
// Supported OpenCL versions
|
||||
enum OclVersion {
|
||||
OpenCL10,
|
||||
OpenCL11,
|
||||
OpenCL12,
|
||||
OpenCL20
|
||||
};
|
||||
|
||||
struct CalFormat {
|
||||
gslChannelOrder channelOrder_; //!< Texel/pixel GSL channel order
|
||||
cmSurfFmt type_; //!< Texel/pixel CAL format
|
||||
};
|
||||
|
||||
struct MemoryFormat {
|
||||
cl_image_format clFormat_; //!< CL image format
|
||||
CalFormat calFormat_; //!< CAL image format
|
||||
};
|
||||
|
||||
static const MemoryFormat
|
||||
MemoryFormatMap[] = {
|
||||
// R
|
||||
{ { CL_R, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_INTENSITY8 } },
|
||||
{ { CL_R, CL_UNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_R16 } },
|
||||
|
||||
{ { CL_R, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_sR8 } },
|
||||
{ { CL_R, CL_SNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_sU16 } },
|
||||
|
||||
{ { CL_R, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_sR8I } },
|
||||
{ { CL_R, CL_SIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_sR16I } },
|
||||
{ { CL_R, CL_SIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_sR32I } },
|
||||
{ { CL_R, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_R8I } },
|
||||
{ { CL_R, CL_UNSIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_R16I } },
|
||||
{ { CL_R, CL_UNSIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_R , CM_SURF_FMT_R32I } },
|
||||
|
||||
{ { CL_R, CL_HALF_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_R16F } },
|
||||
{ { CL_R, CL_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_R, CM_SURF_FMT_R32F } },
|
||||
|
||||
// A
|
||||
{ { CL_A, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_INTENSITY8 } },
|
||||
{ { CL_A, CL_UNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_R16 } },
|
||||
|
||||
{ { CL_A, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_sR8 } },
|
||||
{ { CL_A, CL_SNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_sU16 } },
|
||||
|
||||
{ { CL_A, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_sR8I } },
|
||||
{ { CL_A, CL_SIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_sR16I } },
|
||||
{ { CL_A, CL_SIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_sR32I } },
|
||||
{ { CL_A, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_R8I } },
|
||||
{ { CL_A, CL_UNSIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_R16I } },
|
||||
{ { CL_A, CL_UNSIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_A , CM_SURF_FMT_R32I } },
|
||||
|
||||
{ { CL_A, CL_HALF_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_R16F } },
|
||||
{ { CL_A, CL_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_A, CM_SURF_FMT_R32F } },
|
||||
|
||||
// RG
|
||||
{ { CL_RG, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG8 } },
|
||||
{ { CL_RG, CL_UNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG16 } },
|
||||
|
||||
{ { CL_RG, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_sRG8 } },
|
||||
{ { CL_RG, CL_SNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_sUV16 } },
|
||||
|
||||
{ { CL_RG, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_sRG8I } },
|
||||
{ { CL_RG, CL_SIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_sRG16I } },
|
||||
{ { CL_RG, CL_SIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_sRG32I } },
|
||||
{ { CL_RG, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG8I } },
|
||||
{ { CL_RG, CL_UNSIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG16I } },
|
||||
{ { CL_RG, CL_UNSIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RG , CM_SURF_FMT_RG32I } },
|
||||
|
||||
{ { CL_RG, CL_HALF_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG16F } },
|
||||
{ { CL_RG, CL_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RG, CM_SURF_FMT_RG32F } },
|
||||
|
||||
// RA
|
||||
{ { CL_RA, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG8 } },
|
||||
{ { CL_RA, CL_UNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG16 } },
|
||||
|
||||
{ { CL_RA, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_sRG8 } },
|
||||
{ { CL_RA, CL_SNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_sUV16 } },
|
||||
|
||||
{ { CL_RA, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_sRG8I } },
|
||||
{ { CL_RA, CL_SIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_sRG16I } },
|
||||
{ { CL_RA, CL_SIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_sRG32I } },
|
||||
{ { CL_RA, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG8I } },
|
||||
{ { CL_RA, CL_UNSIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG16I } },
|
||||
{ { CL_RA, CL_UNSIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RA , CM_SURF_FMT_RG32I } },
|
||||
|
||||
{ { CL_RA, CL_HALF_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG16F } },
|
||||
{ { CL_RA, CL_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RA, CM_SURF_FMT_RG32F } },
|
||||
|
||||
// RGBA
|
||||
{ { CL_RGBA, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA8 } },
|
||||
{ { CL_RGBA, CL_UNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA16 } },
|
||||
|
||||
{ { CL_RGBA, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_sRGBA8 } },
|
||||
{ { CL_RGBA, CL_SNORM_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_sUVWQ16 } },
|
||||
|
||||
{ { CL_RGBA, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_sRGBA8I } },
|
||||
{ { CL_RGBA, CL_SIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_sRGBA16I } },
|
||||
{ { CL_RGBA, CL_SIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_sRGBA32I } },
|
||||
{ { CL_RGBA, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA8UI } },
|
||||
{ { CL_RGBA, CL_UNSIGNED_INT16 },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA16UI } },
|
||||
{ { CL_RGBA, CL_UNSIGNED_INT32},
|
||||
{ GSL_CHANNEL_ORDER_RGBA , CM_SURF_FMT_RGBA32UI } },
|
||||
|
||||
{ { CL_RGBA, CL_HALF_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA16F } },
|
||||
{ { CL_RGBA, CL_FLOAT },
|
||||
{ GSL_CHANNEL_ORDER_RGBA, CM_SURF_FMT_RGBA32F } },
|
||||
|
||||
// ARGB
|
||||
{ { CL_ARGB, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_ARGB, CM_SURF_FMT_RGBA8 } },
|
||||
{ { CL_ARGB, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_ARGB, CM_SURF_FMT_sRGBA8 } },
|
||||
{ { CL_ARGB, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_ARGB, CM_SURF_FMT_sRGBA8I } },
|
||||
{ { CL_ARGB, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_ARGB, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// BGRA
|
||||
{ { CL_BGRA, CL_UNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_BGRA, CM_SURF_FMT_RGBA8 } },
|
||||
{ { CL_BGRA, CL_SNORM_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_BGRA, CM_SURF_FMT_sRGBA8 } },
|
||||
{ { CL_BGRA, CL_SIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_BGRA, CM_SURF_FMT_sRGBA8I } },
|
||||
{ { CL_BGRA, CL_UNSIGNED_INT8 },
|
||||
{ GSL_CHANNEL_ORDER_BGRA, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// LUMINANCE
|
||||
{ {CL_LUMINANCE, CL_SNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_sR8 } },
|
||||
{ {CL_LUMINANCE, CL_SNORM_INT16},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_sU16 } },
|
||||
{ {CL_LUMINANCE, CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_INTENSITY8 } },
|
||||
{ {CL_LUMINANCE, CL_UNORM_INT16},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_R16 } },
|
||||
{ {CL_LUMINANCE, CL_HALF_FLOAT},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_R16F } },
|
||||
{ {CL_LUMINANCE, CL_FLOAT},
|
||||
{ GSL_CHANNEL_ORDER_LUMINANCE,CM_SURF_FMT_R32F } },
|
||||
|
||||
// INTENSITY
|
||||
{ {CL_INTENSITY, CL_SNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_sR8 } },
|
||||
{ {CL_INTENSITY, CL_SNORM_INT16},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_sU16 } },
|
||||
{ {CL_INTENSITY, CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_INTENSITY8 } },
|
||||
{ {CL_INTENSITY, CL_UNORM_INT16},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_R16 } },
|
||||
{ {CL_INTENSITY, CL_HALF_FLOAT},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_R16F } },
|
||||
{ {CL_INTENSITY, CL_FLOAT},
|
||||
{ GSL_CHANNEL_ORDER_INTENSITY,CM_SURF_FMT_R32F } },
|
||||
|
||||
// sRBGA
|
||||
{ {CL_sRGBA ,CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_SRGBA, CM_SURF_FMT_RGBA8_SRGB } },
|
||||
{ {CL_sRGBA ,CL_UNSIGNED_INT8}, // This is used only by blit kernel
|
||||
{ GSL_CHANNEL_ORDER_SRGBA, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// sRBG
|
||||
{ {CL_sRGB ,CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_SRGB, CM_SURF_FMT_RGBX8UI } },
|
||||
{ {CL_sRGB ,CL_UNSIGNED_INT8}, // This is used only by blit kernel
|
||||
{ GSL_CHANNEL_ORDER_SRGB, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// sRBGx
|
||||
{ {CL_sRGBx ,CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_SRGBX, CM_SURF_FMT_RGBX8UI } },
|
||||
{ {CL_sRGBx ,CL_UNSIGNED_INT8}, // This is used only by blit kernel
|
||||
{ GSL_CHANNEL_ORDER_SRGBX, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// sBGRA
|
||||
{ {CL_sBGRA ,CL_UNORM_INT8},
|
||||
{ GSL_CHANNEL_ORDER_SBGRA, CM_SURF_FMT_RGBA8 } },
|
||||
{ {CL_sBGRA ,CL_UNSIGNED_INT8}, // This is used only by blit kernel
|
||||
{ GSL_CHANNEL_ORDER_SBGRA, CM_SURF_FMT_RGBA8UI } },
|
||||
|
||||
// DEPTH
|
||||
{ {CL_DEPTH ,CL_FLOAT},
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_DEPTH32F}},
|
||||
{ {CL_DEPTH ,CL_UNSIGNED_INT32}, // This is used only by blit kernel
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_R32I}},
|
||||
|
||||
{ {CL_DEPTH ,CL_UNORM_INT16},
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_DEPTH16}},
|
||||
{ {CL_DEPTH ,CL_UNSIGNED_INT16}, // This is used only by blit kernel
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_R16I}},
|
||||
|
||||
{ {CL_DEPTH_STENCIL ,CL_UNORM_INT24},
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_DEPTH24_STEN8}},
|
||||
{ {CL_DEPTH_STENCIL ,CL_FLOAT},
|
||||
{GSL_CHANNEL_ORDER_REPLICATE_R ,CM_SURF_FMT_DEPTH32F_X24_STEN8}}
|
||||
|
||||
};
|
||||
|
||||
struct MemFormatStruct {
|
||||
cmSurfFmt format_;
|
||||
uint size_;
|
||||
uint components_;
|
||||
};
|
||||
|
||||
static const MemFormatStruct
|
||||
MemoryFormatSize[] = {
|
||||
{ CM_SURF_FMT_INTENSITY8, 1, 1 },/**< 1 component, normalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RG8, 2, 2 }, /**< 2 component, normalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA8, 4, 4 }, /**< 4 component, normalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA8_SRGB, 4, 4 }, /**< 4 component, normalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_R16, 2, 1 }, /**< 1 component, normalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_RG16, 4, 2 }, /**< 2 component, normalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA16, 8, 4 }, /**< 4 component, normalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRGBA8, 4, 4 }, /**< 4 component, normalized signed 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_sU16, 2, 1 }, /**< 1 component, normalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sUV16, 4, 2 }, /**< 2 component, normalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sUVWQ16, 8, 4 }, /**< 4 component, normalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_R32F, 4, 1 }, /**< A 1 component, 32-bit float value per component */
|
||||
{ CM_SURF_FMT_RG32F, 8, 2 }, /**< A 2 component, 32-bit float value per component */
|
||||
{ CM_SURF_FMT_RGBA32F, 16, 4 }, /**< A 4 component, 32-bit float value per component */
|
||||
{ CM_SURF_FMT_sR8, 1, 1 }, /**< 1 component, normalized signed 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRG8, 2, 2 }, /**< 2 component, normalized signed 8-bit integer value per component */
|
||||
|
||||
{ CM_SURF_FMT_R8I, 1, 1 }, /**< 1 component, unnormalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RG8I, 2, 2 }, /**< 2 component, unnormalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA8UI, 4, 4 }, /**< 4 component, unnormalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBX8UI, 4, 4 }, /**< 4 component, unnormalized unsigned 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_sR8I, 1, 1 }, /**< 1 component, unnormalized signed 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRG8I, 2, 2 }, /**< 2 component, unnormalized signed 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRGBA8I, 4, 4 }, /**< 4 component, unnormalized signed 8-bit integer value per component */
|
||||
{ CM_SURF_FMT_R16I, 2, 1 }, /**< 1 component, unnormalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_RG16I, 4, 2 }, /**< 2 component, unnormalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA16UI, 8, 4 }, /**< 4 component, unnormalized unsigned 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sR16I, 2, 1 }, /**< 1 component, unnormalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRG16I, 4, 2 }, /**< 2 component, unnormalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRGBA16I, 8, 4 }, /**< 4 component, unnormalized signed 16-bit integer value per component */
|
||||
{ CM_SURF_FMT_R32I, 4, 1 }, /**< 1 component, unnormalized unsigned 32-bit integer value per component */
|
||||
{ CM_SURF_FMT_RG32I, 8, 2 }, /**< 2 component, unnormalized unsigned 32-bit integer value per component */
|
||||
{ CM_SURF_FMT_RGBA32UI, 16, 4 }, /**< 4 component, unnormalized unsigned 32-bit integer value per component */
|
||||
{ CM_SURF_FMT_sR32I, 4, 1 }, /**< 1 component, unnormalized signed 32-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRG32I, 8, 2 }, /**< 2 component, unnormalized signed 32-bit integer value per component */
|
||||
{ CM_SURF_FMT_sRGBA32I, 16, 4 }, /**< 4 component, unnormalized signed 32-bit integer value per component */
|
||||
|
||||
{ CM_SURF_FMT_R16F, 2, 1 }, /**< A 1 component, 16-bit float value per component */
|
||||
{ CM_SURF_FMT_RG16F, 4, 2 }, /**< A 2 component, 16-bit float value per component */
|
||||
{ CM_SURF_FMT_RGBA16F, 8, 4 }, /**< A 4 component, 16-bit float value per component */
|
||||
|
||||
{ CM_SURF_FMT_DEPTH32F, 4, 1 }, /**< A one component, 32 float value per component */
|
||||
{ CM_SURF_FMT_DEPTH16 , 2, 1 }, /**< A one component, 16 unsigned int value per component */
|
||||
{ CM_SURF_FMT_DEPTH24_STEN8 , 4 ,1}, /**< A one component, 32 float value per component */
|
||||
{ CM_SURF_FMT_DEPTH32F_X24_STEN8 , 8 ,2} /**< depth + stencil, 64 bits per element packed as (@c XXXXXXXXXXXXXXXXXXXXXXXXSSSSSSSSDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD) */
|
||||
};
|
||||
|
||||
__inline const MemFormatStruct&
|
||||
memoryFormatSize(cmSurfFmt fmt)
|
||||
{
|
||||
for (uint i = 0; i < sizeof(MemoryFormatSize) / sizeof(MemFormatStruct); ++i) {
|
||||
if (MemoryFormatSize[i].format_ == fmt) {
|
||||
return MemoryFormatSize[i];
|
||||
}
|
||||
}
|
||||
assert (!"Unknown GSL memory format!");
|
||||
return MemoryFormatSize[0];
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPUDEFS_HPP_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,626 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPU_HPP_
|
||||
#define GPU_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/program.hpp"
|
||||
#include "platform/perfctr.hpp"
|
||||
#include "platform/threadtrace.hpp"
|
||||
#include "platform/memory.hpp"
|
||||
#include "utils/concurrent.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "thread/monitor.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
#include "device/gpu/gpumemory.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpusettings.hpp"
|
||||
#include "device/gpu/gpuappprofile.hpp"
|
||||
|
||||
|
||||
#include "acl.h"
|
||||
#include "vaminterface.h"
|
||||
|
||||
/*! \addtogroup GPU
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
//! A nil device object
|
||||
class NullDevice : public amd::Device
|
||||
{
|
||||
protected:
|
||||
static aclCompiler* compiler_;
|
||||
static aclCompiler* hsaCompiler_;
|
||||
public:
|
||||
aclCompiler* compiler() const { return compiler_; }
|
||||
aclCompiler* hsaCompiler() const { return hsaCompiler_; }
|
||||
|
||||
public:
|
||||
static bool init(void);
|
||||
|
||||
//! Construct a new identifier
|
||||
NullDevice();
|
||||
|
||||
//! Creates an offline device with the specified target
|
||||
bool create(
|
||||
CALtarget target //!< GPU device identifier
|
||||
);
|
||||
|
||||
virtual cl_int createSubDevices(
|
||||
device::CreateSubDevicesInfo& create_info,
|
||||
cl_uint num_entries,
|
||||
cl_device_id* devices,
|
||||
cl_uint* num_devices) {
|
||||
return CL_INVALID_VALUE;
|
||||
}
|
||||
|
||||
//! Instantiate a new virtual device
|
||||
virtual device::VirtualDevice* createVirtualDevice(
|
||||
bool profiling,
|
||||
bool interopQueue
|
||||
#if cl_amd_open_video
|
||||
, void* calVideoProperties = NULL
|
||||
#endif // cl_amd_open_video
|
||||
, uint deviceQueueSize = 0
|
||||
) { return NULL; }
|
||||
|
||||
//! Compile the given source code.
|
||||
virtual device::Program* createProgram(int oclVer = 120);
|
||||
|
||||
//! Just returns NULL for the dummy device
|
||||
virtual device::Memory* createMemory(amd::Memory& owner) const { return NULL; }
|
||||
|
||||
//! Sampler object allocation
|
||||
virtual bool createSampler(
|
||||
const amd::Sampler& owner, //!< abstraction layer sampler object
|
||||
device::Sampler** sampler //!< device sampler object
|
||||
) const
|
||||
{
|
||||
ShouldNotReachHere();
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Just returns NULL for the dummy device
|
||||
virtual device::Memory* createView(
|
||||
amd::Memory& owner, //!< Owner memory object
|
||||
const device::Memory& parent //!< Parent device memory object for the view
|
||||
) const { return NULL; }
|
||||
|
||||
//! Reallocates the provided buffer object
|
||||
virtual bool reallocMemory(amd::Memory& owner) const { return true; }
|
||||
|
||||
//! Acquire external graphics API object in the host thread
|
||||
//! Needed for OpenGL objects on CPU device
|
||||
|
||||
virtual bool bindExternalDevice(
|
||||
intptr_t type, void* pDevice, void* pContext, bool validateOnly) { return true; }
|
||||
|
||||
virtual bool unbindExternalDevice(
|
||||
intptr_t type, void* pDevice, void* pContext, bool validateOnly) { return true; }
|
||||
|
||||
//! Gets a pointer to a region of host-visible memory for use as the target
|
||||
//! of a non-blocking map for a given memory object
|
||||
virtual void* allocMapTarget(
|
||||
amd::Memory& mem, //!< Abstraction layer memory object
|
||||
const amd::Coord3D& origin, //!< The map location in memory
|
||||
const amd::Coord3D& region, //!< The map region in memory
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the mapped memory
|
||||
size_t* slicePitch = NULL //!< Slice for the mapped memory
|
||||
) { return NULL; }
|
||||
|
||||
//! Releases non-blocking map target memory
|
||||
virtual void freeMapTarget(amd::Memory& mem, void* target) {}
|
||||
|
||||
CALtarget calTarget() const { return calTarget_; }
|
||||
|
||||
const AMDDeviceInfo* hwInfo() const { return hwInfo_; }
|
||||
|
||||
//! Empty implementation on Null device
|
||||
virtual bool globalFreeMemory(size_t* freeMemory) const { return false; }
|
||||
|
||||
//! Get GPU device settings
|
||||
const gpu::Settings& settings() const
|
||||
{ return reinterpret_cast<gpu::Settings&>(*settings_); }
|
||||
virtual void* svmAlloc(amd::Context& context, size_t size, size_t alignment, cl_svm_mem_flags flags) const {return NULL;}
|
||||
virtual void svmFree(void* ptr) const {return;}
|
||||
|
||||
protected:
|
||||
CALtarget calTarget_; //!< GPU device identifier
|
||||
const AMDDeviceInfo* hwInfo_; //!< Device HW info structure
|
||||
};
|
||||
|
||||
//! Forward declarations
|
||||
class Command;
|
||||
class Device;
|
||||
class GpuCommand;
|
||||
class Heap;
|
||||
class HeapBlock;
|
||||
class Program;
|
||||
class Kernel;
|
||||
class Memory;
|
||||
class Resource;
|
||||
class VirtualDevice;
|
||||
class PrintfDbg;
|
||||
class ThreadTrace;
|
||||
|
||||
class Sampler : public device::Sampler
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
Sampler(const Device& dev): dev_(dev) {}
|
||||
|
||||
//! Default destructor for the device memory object
|
||||
virtual ~Sampler();
|
||||
|
||||
//! Creates a device sampler from the OCL sampler state
|
||||
bool create(
|
||||
uint32_t oclSamplerState //!< OCL sampler state
|
||||
);
|
||||
|
||||
const void* hwState() const { return hwState_; }
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
Sampler& operator=(const Sampler&);
|
||||
|
||||
//! Disable operator=
|
||||
Sampler(const Sampler&);
|
||||
|
||||
const Device& dev_; //!< Device object associated with the sampler
|
||||
address hwState_; //!< GPU HW state (\todo legacy path)
|
||||
};
|
||||
|
||||
//! A GPU device ordinal (physical GPU device)
|
||||
class Device : public NullDevice, public CALGSLDevice
|
||||
{
|
||||
public:
|
||||
//! Locks any access to the virtual GPUs
|
||||
class ScopedLockVgpus : public amd::StackObject {
|
||||
public:
|
||||
//! Default constructor
|
||||
ScopedLockVgpus(const Device& dev);
|
||||
|
||||
//! Destructor
|
||||
~ScopedLockVgpus();
|
||||
|
||||
private:
|
||||
const Device& dev_; //! Device object
|
||||
};
|
||||
|
||||
//! Interop emulation flags
|
||||
enum InteropEmulationFlags
|
||||
{
|
||||
D3D10Device = 0x00000001,
|
||||
GLContext = 0x00000002,
|
||||
};
|
||||
|
||||
class Engines : public amd::EmbeddedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
Engines() { memset(desc_, 0xff, sizeof(desc_)); }
|
||||
|
||||
//! Creates engine descriptor for this class
|
||||
void create(uint num, gslEngineDescriptor* desc, uint maxNumComputeRings);
|
||||
|
||||
//! Gets engine type mask
|
||||
uint getMask(gslEngineID id) const { return (1 << id); }
|
||||
|
||||
//! Gets a descriptor for the requested engines
|
||||
uint getRequested(uint engines, gslEngineDescriptor* desc) const;
|
||||
|
||||
//! Returns the number of available compute rings
|
||||
uint numComputeRings() const { return numComputeRings_; }
|
||||
|
||||
private:
|
||||
uint numComputeRings_;
|
||||
gslEngineDescriptor desc_[GSL_ENGINEID_MAX]; //!< Engine descriptor
|
||||
};
|
||||
|
||||
//! Transfer buffers
|
||||
class XferBuffers : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
static const size_t MaxXferBufListSize = 8;
|
||||
|
||||
//! Default constructor
|
||||
XferBuffers(const Device& device, Resource::MemoryType type, size_t bufSize)
|
||||
: type_(type)
|
||||
, bufSize_(bufSize)
|
||||
, acquiredCnt_(0)
|
||||
, gpuDevice_(device)
|
||||
{}
|
||||
|
||||
//! Default destructor
|
||||
~XferBuffers();
|
||||
|
||||
//! Creates the xfer buffers object
|
||||
bool create();
|
||||
|
||||
//! Acquires an instance of the transfer buffers
|
||||
Resource& acquire();
|
||||
|
||||
//! Releases transfer buffer
|
||||
void release(
|
||||
VirtualGPU& gpu, //!< Virual GPU object used with the buffer
|
||||
Resource& buffer //!< Transfer buffer for release
|
||||
);
|
||||
|
||||
//! Returns the buffer's size for transfer
|
||||
size_t bufSize() const { return bufSize_; }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
XferBuffers(const XferBuffers&);
|
||||
|
||||
//! Disable assignment operator
|
||||
XferBuffers& operator=(const XferBuffers&);
|
||||
|
||||
//! Get device object
|
||||
const Device& dev() const { return gpuDevice_; }
|
||||
|
||||
Resource::MemoryType type_; //!< The buffer's type
|
||||
size_t bufSize_; //!< Staged buffer size
|
||||
std::list<Resource*> freeBuffers_; //!< The list of free buffers
|
||||
amd::Atomic<uint> acquiredCnt_; //!< The total number of acquired buffers
|
||||
amd::Monitor lock_; //!< Stgaed buffer acquire/release lock
|
||||
const Device& gpuDevice_; //!< GPU device object
|
||||
};
|
||||
|
||||
//! Virtual address cache entry
|
||||
struct VACacheEntry : public amd::HeapObject
|
||||
{
|
||||
void* startAddress_; //!< Start virtual address
|
||||
void* endAddress_; //!< End virtual address
|
||||
Memory* memory_; //!< GPU memory, associated with the range
|
||||
|
||||
//! Constructor
|
||||
VACacheEntry(
|
||||
void* startAddress, //!< Start virtual address
|
||||
void* endAddress, //!< End virtual address
|
||||
Memory* memory //!< GPU memory object
|
||||
): startAddress_(startAddress), endAddress_(endAddress), memory_(memory) {}
|
||||
|
||||
private:
|
||||
//! Disable default constructor
|
||||
VACacheEntry();
|
||||
};
|
||||
|
||||
struct ScratchBuffer : public amd::HeapObject
|
||||
{
|
||||
uint regNum_; //!< The number of used scratch registers
|
||||
std::vector<Memory*> memObjs_; //!< Memory objects for scratch buffers
|
||||
|
||||
//! Default constructor
|
||||
ScratchBuffer(uint numMems): regNum_(0), memObjs_(numMems) {}
|
||||
|
||||
//! Default constructor
|
||||
~ScratchBuffer();
|
||||
|
||||
//! Destroys memory objects
|
||||
void destroyMemory();
|
||||
};
|
||||
|
||||
|
||||
class SrdManager : public amd::HeapObject {
|
||||
public:
|
||||
SrdManager(const Device& dev, uint srdSize, uint bufSize)
|
||||
: dev_(dev)
|
||||
, numFlags_(bufSize / (srdSize * MaskBits))
|
||||
, srdSize_(srdSize)
|
||||
, bufSize_(bufSize) {}
|
||||
~SrdManager();
|
||||
|
||||
//! Allocates a new SRD slot for a resource
|
||||
uint64_t allocSrdSlot(address* cpuAddr);
|
||||
|
||||
//! Frees a SRD slot
|
||||
void freeSrdSlot(uint64_t addr);
|
||||
|
||||
// Fills the resource list for VidMM KMD
|
||||
void fillResourceList(std::vector<const Resource*>& memList);
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
SrdManager(const SrdManager&);
|
||||
|
||||
//! Disable assignment operator
|
||||
SrdManager& operator=(const SrdManager&);
|
||||
|
||||
struct Chunk {
|
||||
Memory* buf_;
|
||||
uint* flags_;
|
||||
Chunk(): buf_(NULL), flags_(NULL) {}
|
||||
};
|
||||
|
||||
static const uint MaskBits = 32;
|
||||
const Device& dev_; //!< GPU device for the chunk manager
|
||||
amd::Monitor ml_; //!< Global lock for the SRD manager
|
||||
std::vector<Chunk> pool_; //!< Pool of SRD buffers
|
||||
uint numFlags_; //!< Total number of flags in array
|
||||
uint srdSize_; //!< SRD size
|
||||
uint bufSize_; //!< Buffer size that holds SRDs
|
||||
};
|
||||
|
||||
//! Initialise the whole GPU device subsystem (CAL init, device enumeration, etc).
|
||||
static bool init();
|
||||
|
||||
//! Shutdown the whole GPU device subsystem (CAL shutdown).
|
||||
static void tearDown();
|
||||
|
||||
//! Construct a new physical GPU device
|
||||
Device();
|
||||
|
||||
//! Initialise a device (i.e. all parts of the constructor that could
|
||||
//! potentially fail)
|
||||
bool create(
|
||||
CALuint ordinal //!< GPU device ordinal index. Starts from 0
|
||||
);
|
||||
|
||||
//! Destructor for the physical GPU device
|
||||
virtual ~Device();
|
||||
|
||||
//! Reallocates current global heap
|
||||
bool reallocHeap(
|
||||
size_t size, //!< requested size for reallocation
|
||||
bool remoteAlloc //!< allocate the new heap in remote memory
|
||||
);
|
||||
|
||||
//! Instantiate a new virtual device
|
||||
device::VirtualDevice* createVirtualDevice(
|
||||
bool profiling,
|
||||
bool interopQueue
|
||||
#if cl_amd_open_video
|
||||
, void* calVideoProperties = NULL
|
||||
#endif // cl_amd_open_video
|
||||
, uint deviceQueueSize = 0
|
||||
);
|
||||
|
||||
//! Memory allocation
|
||||
virtual device::Memory* createMemory(
|
||||
amd::Memory& owner //!< abstraction layer memory object
|
||||
) const;
|
||||
|
||||
//! Sampler object allocation
|
||||
virtual bool createSampler(
|
||||
const amd::Sampler& owner, //!< abstraction layer sampler object
|
||||
device::Sampler** sampler //!< device sampler object
|
||||
) const;
|
||||
|
||||
//! Reallocates the provided buffer object
|
||||
virtual bool reallocMemory(
|
||||
amd::Memory& owner //!< Buffer for reallocation
|
||||
) const;
|
||||
|
||||
//! Allocates a view object from the device memory
|
||||
virtual device::Memory* createView(
|
||||
amd::Memory& owner, //!< Owner memory object
|
||||
const device::Memory& parent //!< Parent device memory object for the view
|
||||
) const;
|
||||
|
||||
//! Create the device program.
|
||||
virtual device::Program* createProgram(int oclVer = 120);
|
||||
|
||||
//! Attempt to bind with external graphics API's device/context
|
||||
virtual bool bindExternalDevice(
|
||||
intptr_t type,
|
||||
void* pDevice,
|
||||
void* pContext,
|
||||
bool validateOnly);
|
||||
|
||||
//! Attempt to unbind with external graphics API's device/context
|
||||
virtual bool unbindExternalDevice(
|
||||
intptr_t type,
|
||||
void* pDevice,
|
||||
void* pContext,
|
||||
bool validateOnly);
|
||||
|
||||
//! Validates kernel before execution
|
||||
virtual bool validateKernel(
|
||||
const amd::Kernel& kernel, //!< AMD kernel object
|
||||
const device::VirtualDevice* vdev
|
||||
);
|
||||
|
||||
//! Gets a pointer to a region of host-visible memory for use as the target
|
||||
//! of a non-blocking map for a given memory object
|
||||
virtual void* allocMapTarget(
|
||||
amd::Memory& mem, //!< Abstraction layer memory object
|
||||
const amd::Coord3D& origin, //!< The map location in memory
|
||||
const amd::Coord3D& region, //!< The map region in memory
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the mapped memory
|
||||
size_t* slicePitch = NULL //!< Slice for the mapped memory
|
||||
);
|
||||
|
||||
//! Retrieves information about free memory on a GPU device
|
||||
virtual bool globalFreeMemory(size_t* freeMemory) const;
|
||||
|
||||
//! Returns a GPU memory object from AMD memory object
|
||||
gpu::Memory* getGpuMemory(
|
||||
amd::Memory* mem //!< Pointer to AMD memory object
|
||||
) const;
|
||||
|
||||
//! Gets the GPU resource associated with the global heap
|
||||
const Resource& globalMem() const { return heap_->resource(); }
|
||||
|
||||
//! Gets the global heap object
|
||||
const Heap* heap() const { return heap_; }
|
||||
|
||||
//! Allocates a heap block from the global heap
|
||||
HeapBlock* allocHeapBlock(
|
||||
size_t size //!< The heap block size for allocation
|
||||
) const;
|
||||
|
||||
//! Gets the memory object for the dummy page
|
||||
amd::Memory* dummyPage() const { return dummyPage_; }
|
||||
|
||||
amd::Monitor& lockAsyncOps() const { return *lockAsyncOps_; }
|
||||
|
||||
//! Returns the lock object for the virtual gpus list
|
||||
amd::Monitor* vgpusAccess() const { return vgpusAccess_; }
|
||||
|
||||
//! Returns the number of virtual GPUs allocated on this device
|
||||
uint numOfVgpus() const { return numOfVgpus_; }
|
||||
uint numOfVgpus_; //!< The number of virtual GPUs (lock protected)
|
||||
|
||||
typedef std::vector<VirtualGPU*> VirtualGPUs;
|
||||
|
||||
//! Returns the list of all virtual GPUs running on this device
|
||||
const VirtualGPUs vgpus() const { return vgpus_; }
|
||||
VirtualGPUs vgpus_; //!< The list of all running virtual gpus (lock protected)
|
||||
|
||||
//! Scratch buffer allocation
|
||||
gpu::Memory* createScratchBuffer(
|
||||
size_t size //!< Size of buffer
|
||||
) const;
|
||||
|
||||
//! Returns transfer buffer object
|
||||
XferBuffers& xferWrite() const { return *xferWrite_; }
|
||||
|
||||
//! Returns transfer buffer object
|
||||
XferBuffers& xferRead() const { return *xferRead_; }
|
||||
|
||||
//! Adds GPU memory to the VA cache list
|
||||
void addVACache(Memory* memory) const;
|
||||
|
||||
//! Removes GPU memory from the VA cache list
|
||||
void removeVACache(const Memory* memory) const;
|
||||
|
||||
//! Finds GPU memory from virtual address
|
||||
Memory* findMemoryFromVA(const void* ptr, size_t* offset) const;
|
||||
|
||||
//! Finds an appropriate map target
|
||||
amd::Memory* findMapTarget(size_t size) const;
|
||||
|
||||
//! Adds a map target to the cache
|
||||
bool addMapTarget(amd::Memory* memory) const;
|
||||
|
||||
//! Returns resource cache object
|
||||
ResourceCache& resourceCache() const { return *resourceCache_; }
|
||||
|
||||
//! Returns engines object
|
||||
const Engines& engines() const { return engines_; }
|
||||
|
||||
//! Returns engines object
|
||||
const device::BlitManager& xferMgr() const { return xferQueue_->blitMgr(); }
|
||||
|
||||
VirtualGPU* xferQueue() const { return xferQueue_; }
|
||||
|
||||
//! Retrieves the internal format from the OCL format
|
||||
CalFormat getCalFormat(
|
||||
const amd::Image::Format& format //! OCL image format
|
||||
) const;
|
||||
|
||||
//! Retrieves the OCL format from the internal image format
|
||||
amd::Image::Format getOclFormat(
|
||||
const CalFormat& format //! Internal image format
|
||||
) const;
|
||||
|
||||
const ScratchBuffer* scratch(uint idx) const { return scratch_[idx]; }
|
||||
|
||||
//! Destroys scratch buffer memory
|
||||
void destroyScratchBuffers();
|
||||
|
||||
//! Initialize heap resources if uninitialized
|
||||
bool initializeHeapResources();
|
||||
|
||||
//! Set GSL sampler to the specified state
|
||||
void fillHwSampler(
|
||||
uint32_t state, //!< Sampler's OpenCL state
|
||||
void* hwState, //!< Sampler's HW state
|
||||
uint32_t hwStateSize //!< Size of sampler's HW state
|
||||
) const;
|
||||
|
||||
//! host memory alloc
|
||||
virtual void* hostAlloc(size_t size, size_t alignment, bool atomics = false) const;
|
||||
|
||||
//! SVM allocation
|
||||
virtual void* svmAlloc(amd::Context& context, size_t size, size_t alignment, cl_svm_mem_flags flags) const;
|
||||
|
||||
//! Free host SVM memory
|
||||
void hostFree(void* ptr, size_t size) const;
|
||||
|
||||
//! SVM free
|
||||
virtual void svmFree(void* ptr) const;
|
||||
|
||||
//! Returns SRD manger object
|
||||
SrdManager& srds() const { return *srdManager_; }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Device(const Device&);
|
||||
|
||||
//! Disable assignment
|
||||
Device& operator=(const Device&);
|
||||
|
||||
//! Sends the stall command to all queues
|
||||
bool stallQueues();
|
||||
|
||||
//! Fills OpenCL device info structure
|
||||
void fillDeviceInfo(
|
||||
const CALdeviceattribs& calAttr, //!< CAL device attributes info
|
||||
const CALdevicestatus& calStatus //!< CAL device status
|
||||
#if cl_amd_open_video
|
||||
,
|
||||
const CALdeviceVideoAttribs& calVideoAttr //!< -"- video attrib. info
|
||||
#endif //cl_amd_open_video
|
||||
);
|
||||
|
||||
//! Buffer allocation from static heap (no VM mode only)
|
||||
gpu::Memory* createBufferFromHeap(
|
||||
amd::Memory& owner //!< Abstraction layer memory object
|
||||
) const;
|
||||
|
||||
//! Buffer allocation
|
||||
gpu::Memory* createBuffer(
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
bool directAccess, //!< Use direct host memory access
|
||||
bool bufferAlloc //!< If TRUE, then don't use heap
|
||||
) const;
|
||||
|
||||
//! Image allocation
|
||||
gpu::Memory* createImage(
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
bool directAccess //!< Use direct host memory access
|
||||
) const;
|
||||
|
||||
//! Allocates/reallocates the scratch buffer, according to the usage
|
||||
bool allocScratch(
|
||||
uint regNum, //!< Number of the scratch registers
|
||||
const VirtualGPU* vgpu //!< Virtual GPU for the allocation
|
||||
);
|
||||
|
||||
amd::Context* context_; //!< A dummy context for internal allocations
|
||||
size_t heapSize_; //!< The global heap size
|
||||
Heap* heap_; //!< GPU heap manager
|
||||
amd::Memory* dummyPage_; //!< A dummy page for NULL pointer
|
||||
|
||||
amd::Monitor* lockAsyncOps_; //!< Lock to serialise all async ops on this device
|
||||
amd::Monitor* lockAsyncOpsForInitHeap_; //!< Lock to serialise all async ops on initialization heap operation
|
||||
amd::Monitor* vgpusAccess_; //!< Lock to serialise virtual gpu list access
|
||||
|
||||
XferBuffers* xferRead_; //!< Transfer buffers read
|
||||
XferBuffers* xferWrite_; //!< Transfer buffers write
|
||||
|
||||
amd::Monitor* vaCacheAccess_; //!< Lock to serialize VA caching access
|
||||
std::list<VACacheEntry*>* vaCacheList_; //!< VA cache list
|
||||
std::vector<amd::Memory*>* mapCache_; //!< Map cache info structure
|
||||
ResourceCache* resourceCache_; //!< CAL resource cache
|
||||
Engines engines_; //!< Available engines on device
|
||||
bool heapInitComplete_; //!< Keep track of initialization status of heap resources
|
||||
VirtualGPU* xferQueue_; //!< Transfer queue
|
||||
std::vector<ScratchBuffer*> scratch_; //!< Scratch buffers for kernels
|
||||
SrdManager* srdManager_; //!< SRD manager object
|
||||
|
||||
static AppProfile appProfile_; //!< application profile
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPU_HPP_*/
|
||||
@@ -0,0 +1,536 @@
|
||||
//! Implementation of GPU device memory management
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/thread.hpp"
|
||||
#include "thread/monitor.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/gpu/gpuheap.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
//! Turn this on to enable sanity checks before and after every heap operation.
|
||||
#if DEBUG
|
||||
#define EXTRA_HEAP_CHECKS 1
|
||||
#endif // DEBUG
|
||||
|
||||
namespace gpu {
|
||||
|
||||
// The GPU heap. Very simple implementation for now.
|
||||
Heap::Heap(
|
||||
Device& device)
|
||||
: resource_(NULL)
|
||||
, freeList_(NULL)
|
||||
, busyList_(NULL)
|
||||
, freeSize_(0)
|
||||
, device_(device)
|
||||
, granularity_(Heap::MinGranularity)
|
||||
, lock_("GPU heap lock", true)
|
||||
, virtualMode_(false)
|
||||
, baseAddress_(0)
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
Heap::granularityB() const
|
||||
{
|
||||
return granularity_ * Heap::ElementSize;
|
||||
}
|
||||
|
||||
bool
|
||||
Heap::create(size_t totalSize, bool remoteAlloc)
|
||||
{
|
||||
Resource::MemoryType memType;
|
||||
size_t maxHeight = device_.info().image2DMaxHeight_;
|
||||
size_t sizeInElements;
|
||||
size_t npages;
|
||||
|
||||
freeSize_ = totalSize;
|
||||
|
||||
sizeInElements = (totalSize + Heap::ElementSize - 1) / Heap::ElementSize;
|
||||
|
||||
// Calculate best granularity given the size and device characteristics
|
||||
npages = amd::alignUp(sizeInElements, granularity_) / granularity_;
|
||||
|
||||
// Create a new GPU resource
|
||||
resource_ = new Resource(device_, sizeInElements, Heap::ElementType);
|
||||
|
||||
if (resource_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memType = (remoteAlloc) ? Resource::RemoteUSWC : Resource::Local;
|
||||
|
||||
if (!resource_->create(memType, NULL, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set up initial free list
|
||||
freeList_ = new HeapBlock(this, npages * granularityB(), 0, NULL, NULL);
|
||||
if (freeList_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
guarantee(isSane());
|
||||
return true;
|
||||
}
|
||||
|
||||
Heap::~Heap()
|
||||
{
|
||||
amd::ScopedLock k(lock_);
|
||||
|
||||
guarantee(isSane());
|
||||
|
||||
// Release all heap blocks
|
||||
HeapBlock *walk, *next;
|
||||
walk = busyList_;
|
||||
while (walk) {
|
||||
next = walk->next_;
|
||||
walk->free();
|
||||
walk = next;
|
||||
}
|
||||
|
||||
walk = freeList_;
|
||||
while (walk) {
|
||||
next = walk->next_;
|
||||
delete walk;
|
||||
walk = next;
|
||||
}
|
||||
|
||||
// Release resource
|
||||
delete resource_;
|
||||
}
|
||||
|
||||
HeapBlock*
|
||||
Heap::alloc(size_t size)
|
||||
{
|
||||
amd::ScopedLock k(lock_);
|
||||
HeapBlock* walk = freeList_;
|
||||
HeapBlock* best = NULL;
|
||||
|
||||
guarantee(isSane());
|
||||
|
||||
// Round size
|
||||
size = amd::alignUp(size, granularityB());
|
||||
|
||||
// Walk the free list looking for a suitable block (currently best-fit)
|
||||
//! @todo:dgladdin: experiment with switching back to first-fit
|
||||
|
||||
while (walk) {
|
||||
if ((walk->size_ > size) &&
|
||||
(best == NULL || walk->size_ < best->size_)) {
|
||||
best = walk;
|
||||
}
|
||||
else if (walk->size_ == size) {
|
||||
// No need to split, just move to busy list
|
||||
detachBlock(&freeList_, walk);
|
||||
walk->inUse_ = true;
|
||||
insertBlock(&busyList_, walk);
|
||||
guarantee(isSane());
|
||||
freeSize_ -= size;
|
||||
return walk;
|
||||
}
|
||||
walk = walk->next_;
|
||||
}
|
||||
|
||||
if (best != NULL) {
|
||||
// Got one, but need to split it. Keep first part in free list,
|
||||
// put second part into busy list.
|
||||
HeapBlock *newblock = splitBlock(best, size);
|
||||
newblock->inUse_ = true;
|
||||
insertBlock(&busyList_, newblock);
|
||||
guarantee(isSane());
|
||||
freeSize_ -= size;
|
||||
return newblock;
|
||||
}
|
||||
|
||||
// No free block available
|
||||
guarantee(isSane());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
Heap::copyTo(Heap* heap)
|
||||
{
|
||||
HeapBlock *walk;
|
||||
|
||||
walk = busyList_;
|
||||
while (walk) {
|
||||
if (walk->getMemory() != NULL) {
|
||||
HeapBlock* hb = heap->alloc(walk->size_);
|
||||
if (hb == NULL) {
|
||||
return false;
|
||||
}
|
||||
hb->setMemory(walk->getMemory());
|
||||
|
||||
walk->destroyViewsMemory();
|
||||
if (!walk->getMemory()->reallocate(hb, &(heap->resource()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!walk->reallocateViews(hb,
|
||||
static_cast<size_t>(hb->offset_ - walk->offset_))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
walk = walk->next_;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Heap::free(HeapBlock* blk)
|
||||
{
|
||||
amd::ScopedLock k(lock_);
|
||||
guarantee(isSane());
|
||||
detachBlock(&busyList_, blk);
|
||||
blk->inUse_ = false;
|
||||
freeSize_ += blk->size_;
|
||||
mergeBlock(&freeList_, blk);
|
||||
guarantee(isSane());
|
||||
}
|
||||
|
||||
void
|
||||
Heap::detachBlock(HeapBlock** list, HeapBlock* blk)
|
||||
{
|
||||
// Sanity checks
|
||||
guarantee(isSane());
|
||||
|
||||
if (*list == blk) {
|
||||
*list = blk->next_;
|
||||
}
|
||||
|
||||
if (blk->prev_) {
|
||||
blk->prev_->next_ = blk->next_;
|
||||
}
|
||||
if (blk->next_) {
|
||||
blk->next_->prev_ = blk->prev_;
|
||||
}
|
||||
// no heap sanity check as blk is now floating
|
||||
}
|
||||
|
||||
void
|
||||
Heap::insertBlock(HeapBlock** head, HeapBlock* blk)
|
||||
{
|
||||
if (NULL == *head) {
|
||||
*head = blk;
|
||||
blk->prev_ = NULL;
|
||||
blk->next_ = NULL;
|
||||
guarantee(isSane());
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the place to insert it at
|
||||
HeapBlock* walk = *head;
|
||||
while (walk->next_ && walk->next_->offset_ < blk->offset_) {
|
||||
walk = walk->next_;
|
||||
}
|
||||
|
||||
// Insert it
|
||||
if (walk == *head) {
|
||||
if (walk->offset_ >= blk->offset_) {
|
||||
*head = blk;
|
||||
blk->prev_ = NULL;
|
||||
blk->next_ = walk;
|
||||
walk->prev_ = *head;
|
||||
guarantee(isSane());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
blk->next_ = walk->next_;
|
||||
blk->prev_ = walk;
|
||||
if (walk->next_) {
|
||||
walk->next_->prev_ = blk;
|
||||
}
|
||||
walk->next_ = blk;
|
||||
guarantee(isSane());
|
||||
}
|
||||
|
||||
HeapBlock*
|
||||
Heap::splitBlock(HeapBlock* blk, size_t tailsize)
|
||||
{
|
||||
// Sanity checks
|
||||
|
||||
guarantee(isSane());
|
||||
guarantee(blk->size_ > tailsize && "block too small to split as requested");
|
||||
guarantee(!blk->inUse_ && "can't split in-use block");
|
||||
|
||||
// Create a new block
|
||||
|
||||
HeapBlock* nb = new HeapBlock(blk->owner_, tailsize,
|
||||
blk->offset_ + blk->size_ - tailsize);
|
||||
|
||||
// Resize the old block
|
||||
|
||||
blk->size_ = blk->size_ - tailsize;
|
||||
return nb; // no heap sanity check here as the new block hasn't been plugged in yet
|
||||
}
|
||||
|
||||
//! Join two blocks, transferring the size of the second into the first and deleting
|
||||
//! the second. Utility fn for mergeBlock()
|
||||
|
||||
static void
|
||||
join2Blocks(HeapBlock* first, HeapBlock* second)
|
||||
{
|
||||
// Sanity checks
|
||||
|
||||
guarantee(first->size_ > 0 && "first block invalid");
|
||||
guarantee(!first->inUse_ && "can't join an in-use block");
|
||||
guarantee(second->size_ > 0 && "second block invalid");
|
||||
guarantee(first->offset_ + first->size_ == second->offset_);
|
||||
|
||||
// Do the join
|
||||
first->size_ = first->size_ + second->size_;
|
||||
first->next_ = second->next_;
|
||||
if (second->next_) {
|
||||
second->next_->prev_ = first;
|
||||
}
|
||||
delete second;
|
||||
}
|
||||
|
||||
//! Insert a block into a list, merging it with adjacent blocks if possible. Must be called
|
||||
//! under a lock, cannot be used on in-use blocks or blocks with an associated resource alias.
|
||||
|
||||
void
|
||||
Heap::mergeBlock(HeapBlock** head, HeapBlock* blk)
|
||||
{
|
||||
insertBlock(head, blk);
|
||||
|
||||
// Merge with successor if possible
|
||||
if ((blk->next_ != NULL) &&
|
||||
(blk->offset_ + blk->size_ == blk->next_->offset_)) {
|
||||
join2Blocks(blk, blk->next_);
|
||||
}
|
||||
|
||||
// Merge with predecessor if possible
|
||||
if ((blk->prev_ != NULL) &&
|
||||
(blk->prev_->offset_ + blk->prev_->size_ == blk->offset_)) {
|
||||
join2Blocks(blk->prev_, blk);
|
||||
}
|
||||
|
||||
guarantee(isSane());
|
||||
}
|
||||
|
||||
//! Sanity check for both types of block (helper function for Heap::isSane())
|
||||
|
||||
static bool
|
||||
isBlockSane(HeapBlock* b)
|
||||
{
|
||||
return (b->owner_ != NULL
|
||||
&& (b->next_ == NULL || b->next_->prev_ == b)
|
||||
&& (b->prev_ == NULL || b->prev_->next_ == b));
|
||||
}
|
||||
|
||||
//! Sanity check for an individual free block (helper function for Heap::isSane())
|
||||
static bool
|
||||
isFreeBlockSane(HeapBlock* b)
|
||||
{
|
||||
if (isBlockSane(b) && !b->inUse_) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! Sanity check for an individual busy block (helper function for Heap::isSane())
|
||||
static bool
|
||||
isBusyBlockSane(HeapBlock* b)
|
||||
{
|
||||
if (isBlockSane(b) && b->inUse_) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! Sanity check for the heap.
|
||||
|
||||
bool
|
||||
Heap::isSane() const
|
||||
{
|
||||
// If we got this far, everything is (probably) OK
|
||||
#if EXTRA_HEAP_CHECKS
|
||||
HeapBlock* walkFree = freeList_; // Free list position
|
||||
HeapBlock* walkBusy = busyList_; // Busy list position
|
||||
size_t offset = 0; // Current offset
|
||||
|
||||
// We can have zero lists if Heap allocation fails
|
||||
if (walkFree == NULL && walkBusy == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Walk both lists in parallel
|
||||
while (walkFree != NULL || walkBusy != NULL) {
|
||||
if (walkFree != NULL && walkFree->offset_ == offset) {
|
||||
if (!isFreeBlockSane(walkFree)) {
|
||||
return false;
|
||||
}
|
||||
offset += walkFree->size_;
|
||||
walkFree = walkFree->next_;
|
||||
}
|
||||
else if (walkBusy != NULL && walkBusy->offset_ == offset) {
|
||||
if (!isBusyBlockSane(walkBusy)) {
|
||||
return false;
|
||||
}
|
||||
offset += walkBusy->size_;
|
||||
walkBusy = walkBusy->next_;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // EXTRA_HEAP_CHECKS
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HeapBlock::destroyViewsMemory()
|
||||
{
|
||||
if ((parent_ != NULL) && (0 == views_.size())) {
|
||||
memory_->free();
|
||||
}
|
||||
else if (views_.size() != 0) {
|
||||
std::list<HeapBlock*>::const_iterator it;
|
||||
for (it = views_.begin(); it != views_.end(); ++it) {
|
||||
(*it)->destroyViewsMemory();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HeapBlock::reallocateViews(HeapBlock* parent, size_t shift)
|
||||
{
|
||||
if (views_.size() != 0) {
|
||||
std::list<HeapBlock*>::const_iterator it;
|
||||
|
||||
// Loop through all views and reallocate them
|
||||
for (it = views_.begin(); it != views_.end(); ++it) {
|
||||
// Get the view HeapBlock
|
||||
HeapBlock* hb = (*it);
|
||||
|
||||
// Readjust the offset
|
||||
hb->offset_ += shift;
|
||||
// Add to the list if we have a new parent
|
||||
if (parent != this) {
|
||||
parent->addView(hb);
|
||||
}
|
||||
|
||||
// Reallocate memory
|
||||
hb->memory_->reallocate(hb, parent->getMemory());
|
||||
|
||||
// Process a view on view if available
|
||||
if (!hb->reallocateViews(hb, shift)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy old list
|
||||
if (parent != this) {
|
||||
views_.clear();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Destructor. Frees the block if in use and does some final sanity checks.
|
||||
HeapBlock::~HeapBlock()
|
||||
{
|
||||
if (NULL != owner_) {
|
||||
if (inUse_) {
|
||||
owner_->free(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// View destruction
|
||||
if (parent_ != NULL) {
|
||||
assert(((parent_->getMemory() != NULL) && (parent_->getMemory()->owner() != NULL)));
|
||||
amd::ScopedLock lock(parent_->getMemory()->owner()->lockMemoryOps());
|
||||
parent_->removeView(this);
|
||||
}
|
||||
}
|
||||
guarantee(size_ > 0 && "destructor called for zero-size heap block (destructor called twice?)");
|
||||
size_ = 0; // Mark as invalid
|
||||
|
||||
if (views_.size() != 0) {
|
||||
LogError("Can't destroy a resource if we still have views!");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HeapBlock::free()
|
||||
{
|
||||
if (NULL != owner_) {
|
||||
owner_->free(this);
|
||||
}
|
||||
else {
|
||||
// It's a view. Destroy the object
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualHeap::VirtualHeap(
|
||||
Device& device)
|
||||
: Heap(device)
|
||||
{
|
||||
virtualMode_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
VirtualHeap::create(
|
||||
size_t totalSize,
|
||||
bool remoteAlloc)
|
||||
{
|
||||
// Create a new GPU resource
|
||||
resource_ = new Resource(device_, 0, Heap::ElementType);
|
||||
if (resource_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!resource_->create(Resource::Heap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device_.settings().hsail_) {
|
||||
baseAddress_ = resource_->gslResource()->getSurfaceAddress();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VirtualHeap::~VirtualHeap()
|
||||
{
|
||||
}
|
||||
|
||||
HeapBlock*
|
||||
VirtualHeap::alloc(size_t size)
|
||||
{
|
||||
assert(false && "Dead branch!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
VirtualHeap::free(HeapBlock* blk)
|
||||
{
|
||||
assert(false && "Dead branch!");
|
||||
}
|
||||
|
||||
bool
|
||||
VirtualHeap::copyTo(Heap* heap)
|
||||
{
|
||||
assert(false && "Dead branch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
VirtualHeap::isSane(void) const
|
||||
{
|
||||
assert(false && "Dead branch!");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,225 @@
|
||||
//! Declarations for GPU memory management
|
||||
|
||||
#ifndef GPUHEAP_HPP_
|
||||
#define GPUHEAP_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
|
||||
/*! \addtogroup GPU
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class Heap;
|
||||
class Resource;
|
||||
class Memory;
|
||||
class VirtualGPU;
|
||||
|
||||
//! @todo:dgladdin: The heap list should be singly-linked
|
||||
|
||||
//! \brief A block on the GPU heap.
|
||||
//!
|
||||
//! Note that no code outside of the gpumemory.hpp/.cpp pair should touch this
|
||||
//! class directly as it is not thread-safe. In general, this class should be
|
||||
//! pretty much a struct and contain as little functionality as possible - just
|
||||
//! a constructor, destructor.
|
||||
//!
|
||||
//! Any other methods - in particular, anything that talks to CAL - should be no
|
||||
//! more than proxies for functionality implemented in Heap, as Heap is aware
|
||||
//! of the lock state.
|
||||
|
||||
class HeapBlock : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
HeapBlock(
|
||||
Heap* owner = NULL,
|
||||
size_t size = 0,
|
||||
size_t offset = 0,
|
||||
HeapBlock* next=NULL,
|
||||
HeapBlock* prev=NULL)
|
||||
: owner_(owner)
|
||||
, size_(size)
|
||||
, offset_(offset)
|
||||
, next_(next)
|
||||
, prev_(prev)
|
||||
, inUse_(false)
|
||||
, parent_(NULL)
|
||||
, memory_(NULL)
|
||||
{}
|
||||
|
||||
//! Destructor does some sanity checks.
|
||||
~HeapBlock();
|
||||
|
||||
//! Frees a heap block, returning its memory to the owning heap (proxy)
|
||||
void free();
|
||||
|
||||
//! Sets the GPU memory object associated with the heap block
|
||||
void setMemory(Memory* memory) { memory_ = memory; }
|
||||
|
||||
//! Gets the GPU memory object associated with the heap block
|
||||
Memory* getMemory() const { return memory_; }
|
||||
|
||||
//! Adds a heapblock view to the list of views
|
||||
void addView(HeapBlock* hb)
|
||||
{ views_.push_back(hb); hb->parent_ = this; }
|
||||
|
||||
//! Removes a heapblock view from the list of views
|
||||
void removeView(HeapBlock* hb) { views_.remove(hb); }
|
||||
|
||||
//! Destroys all views
|
||||
void destroyViewsMemory();
|
||||
|
||||
//! Creates all new views
|
||||
bool reallocateViews(
|
||||
HeapBlock* parent, //!< Parent heap block
|
||||
size_t shift //!< The new HeapBlock shift
|
||||
);
|
||||
|
||||
//! Gets the offset
|
||||
size_t offset() const { return offset_; }
|
||||
|
||||
Heap* owner_; //!< Heap that owns this block
|
||||
size_t size_; //!< Size of the block in bytes
|
||||
size_t offset_; //!< Offset of this block in the heap
|
||||
HeapBlock* next_; //!< Next block on the list, or NULL
|
||||
HeapBlock* prev_; //!< Previous block on the list, or NULL
|
||||
bool inUse_; //!< true if the block is in use
|
||||
HeapBlock* parent_; //!< The parent heap block for a view
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
HeapBlock(const HeapBlock&);
|
||||
|
||||
//! Disable assignment
|
||||
HeapBlock& operator=(const HeapBlock&);
|
||||
|
||||
Memory* memory_; //!< Memory object associated with the heap block
|
||||
std::list<HeapBlock*> views_; //!< The list of all allocated views
|
||||
};
|
||||
|
||||
class Heap : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Minimal supported CAL granularity = 256 bytes / ElementSize
|
||||
static const size_t MinGranularity = 64;
|
||||
|
||||
//! The size of a heap element in bytes
|
||||
static const size_t ElementSize = 4;
|
||||
|
||||
//! The type of a heap element in bytes
|
||||
static const cmSurfFmt ElementType = CM_SURF_FMT_R32I;
|
||||
|
||||
Heap(
|
||||
Device& device //!< GPU device object
|
||||
);
|
||||
|
||||
virtual bool create(
|
||||
size_t totalSize, //!< total size of the allocated heap (bytes)
|
||||
bool remoteAlloc //!< allocate the heap in remote memory
|
||||
);
|
||||
|
||||
//! Heap destructor
|
||||
virtual ~Heap();
|
||||
|
||||
/*!
|
||||
* \brief Allocates memory from a heap (best-fit).
|
||||
* We round up to 4k granularity for alignment.
|
||||
*
|
||||
* \return A pointer to allocated heap block object.
|
||||
*/
|
||||
virtual HeapBlock* alloc(
|
||||
size_t size //! The allocation size
|
||||
);
|
||||
|
||||
//! Release memory back to a heap.
|
||||
virtual void free(HeapBlock* blk);
|
||||
|
||||
//! Copies this heap to another
|
||||
virtual bool copyTo(Heap* heap);
|
||||
|
||||
//! Gets the GPU resource associated with the global heap
|
||||
const Resource& resource() const { return *resource_; }
|
||||
|
||||
//! Read the page size (bytes)
|
||||
size_t granularityB() const;
|
||||
|
||||
//! Read the total free space (bytes)
|
||||
size_t freeSpace() const { return freeSize_; }
|
||||
|
||||
virtual bool isSane(void) const; //!< Checks heap sanity
|
||||
|
||||
//! Returns true if we have a virtual heap
|
||||
bool isVirtual() const { return virtualMode_; }
|
||||
|
||||
//! Returns the base virtual address of the heap
|
||||
uint64_t baseAddress() const { return baseAddress_; }
|
||||
|
||||
private:
|
||||
//! Insert a block into a list. Must be called under a lock.
|
||||
void insertBlock(HeapBlock** list, HeapBlock* node);
|
||||
|
||||
//! Merge a block into a list. Must be called under a lock.
|
||||
void mergeBlock(HeapBlock** list, HeapBlock* node);
|
||||
|
||||
//! Remove a block from a list. Must be called under a lock.
|
||||
void detachBlock(HeapBlock** list, HeapBlock* node);
|
||||
|
||||
//! Split a block into two pieces
|
||||
HeapBlock* splitBlock(HeapBlock* node, size_t size);
|
||||
|
||||
protected:
|
||||
Resource* resource_; //!< GPU resource referencing the heap memory
|
||||
HeapBlock* freeList_; //!< Head block for free list
|
||||
HeapBlock* busyList_; //!< Head block for busy list
|
||||
size_t freeSize_; //!< total free size of the heap
|
||||
Device& device_; //!< Device that owns this heap
|
||||
size_t granularity_; //!< Size of an allocation page
|
||||
amd::Monitor lock_; //!< Lock to serialise heap accesses
|
||||
bool virtualMode_; //!< Virtual mode
|
||||
uint64_t baseAddress_; //!< Virtual heap base address
|
||||
};
|
||||
|
||||
class VirtualHeap : public Heap
|
||||
{
|
||||
public:
|
||||
VirtualHeap(
|
||||
Device& device //!< GPU device object
|
||||
);
|
||||
|
||||
virtual bool create(
|
||||
size_t totalSize, //!< total size of the allocated heap (bytes)
|
||||
bool remoteAlloc //!< allocate the heap in remote memory
|
||||
);
|
||||
|
||||
//! Heap destructor
|
||||
virtual ~VirtualHeap();
|
||||
|
||||
/*!
|
||||
* \brief Allocates memory from a heap (best-fit).
|
||||
* We round up to 4k granularity for alignment.
|
||||
*
|
||||
* \return A pointer to allocated heap block object.
|
||||
*/
|
||||
virtual HeapBlock* alloc(
|
||||
size_t size //! The allocation size
|
||||
);
|
||||
|
||||
//! Release memory back to a heap.
|
||||
virtual void free(HeapBlock* blk);
|
||||
|
||||
//! Copies this heap to another
|
||||
virtual bool copyTo(Heap* heap);
|
||||
|
||||
virtual bool isSane(void) const; //!< Checks heap sanity
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPUHEAP_HPP_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,960 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUKERNEL_HPP_
|
||||
#define GPUKERNEL_HPP_
|
||||
|
||||
#include "device/device.hpp"
|
||||
#include "utils/macros.hpp"
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/program.hpp"
|
||||
#include "platform/kernel.hpp"
|
||||
#include "platform/sampler.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
#include "sc-hsa/Interface/SCHSAInterface.h"
|
||||
#include "device/gpu/gpuprintf.hpp"
|
||||
#include "newcore.h"
|
||||
//! \namespace gpu GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
class VirtualGPU;
|
||||
class Device;
|
||||
class NullDevice;
|
||||
class HSAILProgram;
|
||||
|
||||
struct HWSHADER_Helper
|
||||
{
|
||||
template <typename S, typename T>
|
||||
static T Get(S base, T offset) {
|
||||
return reinterpret_cast<T>(reinterpret_cast<intptr_t>(base)
|
||||
+ reinterpret_cast<size_t>(offset));
|
||||
}
|
||||
};
|
||||
|
||||
#define HWSHADER_Get(shader, field) \
|
||||
HWSHADER_Helper::Get((shader), (shader)->field)
|
||||
|
||||
template <typename D, typename S>
|
||||
static void CalcPtr(D& dst, const S src, size_t structSize, size_t size) {
|
||||
dst = reinterpret_cast<D>(reinterpret_cast<const intptr_t>(src)
|
||||
+ structSize * size);
|
||||
}
|
||||
|
||||
/*! \addtogroup GPU GPU Device Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Finds the name in the std::string
|
||||
*
|
||||
* \return True if we found the entry of the symbols
|
||||
*/
|
||||
bool expect(
|
||||
const std::string& str, //!< The original std::string
|
||||
size_t* pos, //!< Position to start
|
||||
const std::string& sym //!< The sympols to expect
|
||||
);
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Gets a word from the std::string
|
||||
*
|
||||
* \return True if we successfully received a word
|
||||
*/
|
||||
bool getword(
|
||||
const std::string& str, //!< The original std::string
|
||||
size_t* pos, //!< Position to start
|
||||
char* sym //!< Returned word
|
||||
);
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Loads numbers from the metadata
|
||||
*
|
||||
* \return True if we loaded a number
|
||||
*/
|
||||
bool getuint(
|
||||
const std::string& str, //!< The original std::string
|
||||
size_t* pos, //!< Position to start
|
||||
uint* val //!< Returned number
|
||||
);
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Loads numbers from the metadata in HEX format
|
||||
*
|
||||
* \return True if we loaded a number
|
||||
*/
|
||||
bool getuintHex(
|
||||
const std::string& str, //!< The original std::string
|
||||
size_t* pos, //!< Position to start
|
||||
uint* val //!< Returned number
|
||||
);
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Loads numbers from the metadata in HEX format
|
||||
*
|
||||
* \return True if we loaded a number
|
||||
*/
|
||||
bool getuint64Hex(
|
||||
const std::string& str, //!< The original std::string
|
||||
size_t* pos, //!< Position to start
|
||||
uint64_t* val //!< Returned number
|
||||
);
|
||||
|
||||
/*! \brief Helper function for the std::string processing.
|
||||
* Converts unsigned integer to string
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
void intToStr(
|
||||
size_t value, //!< Value for conversion
|
||||
char* str, //!< Pointer to the converted string
|
||||
size_t size //!< String size
|
||||
);
|
||||
|
||||
//! Image constant data from ABI specification
|
||||
struct ImageConstants : public amd::EmbeddedObject
|
||||
{
|
||||
uint32_t width_; //!< Image surface width
|
||||
uint32_t height_; //!< Image surface height
|
||||
uint32_t depth_; //!< Image surface depth (1 for 2D images)
|
||||
uint32_t dataType_; //!< Image surface data type
|
||||
float widthFloat_; //!< Image surface width
|
||||
float heightFloat_; //!< Image surface height
|
||||
float depthFloat_; //!< Image surface depth (1 for 2D images)
|
||||
uint32_t channelOrder_; //!< Image surface texels channel order
|
||||
};
|
||||
|
||||
//! Kernel arguments
|
||||
struct KernelArg : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! \enum Kernel argument type
|
||||
enum ArgumentType
|
||||
{
|
||||
None = 0,
|
||||
PointerGlobal,
|
||||
Value,
|
||||
Image,
|
||||
PointerLocal,
|
||||
PointerHwLocal,
|
||||
PointerPrivate,
|
||||
PointerHwPrivate,
|
||||
PointerConst,
|
||||
PointerHwConst,
|
||||
Float,
|
||||
Double,
|
||||
Half,
|
||||
Char,
|
||||
UChar,
|
||||
Short,
|
||||
UShort,
|
||||
Int,
|
||||
UInt,
|
||||
Long,
|
||||
ULong,
|
||||
Struct,
|
||||
Union,
|
||||
Opaque,
|
||||
Event,
|
||||
Image1D, //!< first image
|
||||
Image2D,
|
||||
Image1DB,
|
||||
Image1DA,
|
||||
Image2DA,
|
||||
Image3D, //!< last image
|
||||
Counter,
|
||||
Sampler,
|
||||
PrivateSize,
|
||||
LocalSize,
|
||||
HwPrivateSize,
|
||||
HwLocalSize,
|
||||
Grouping,
|
||||
WrkgrpSize,
|
||||
Wavefront,
|
||||
PrivateFixed,
|
||||
ErrorMessage,
|
||||
WarningMessage,
|
||||
PrintfFormatStr,
|
||||
MetadataVersion,
|
||||
UavId,
|
||||
ABI64Bit,
|
||||
GWS,
|
||||
SWGWS,
|
||||
Reflection,
|
||||
ConstArg,
|
||||
ConstBufId,
|
||||
PrintfBufId,
|
||||
GroupingHint,
|
||||
VecTypeHint,
|
||||
TotalTypes
|
||||
};
|
||||
|
||||
// The compiler metadata fields
|
||||
std::string name_; //!< parameters name
|
||||
ArgumentType type_; //!< type of argument
|
||||
union {
|
||||
uint size_; //!< number of arguments (for values and pointers only)
|
||||
uint location_; //!< sampler's location (for samplers only)
|
||||
};
|
||||
uint cbIdx_; //!< constant buffer index
|
||||
uint cbPos_; //!< dword address in CB for the argument
|
||||
std::string buf_; //!< buffer tag
|
||||
uint index_; //!< buffer/image/sampler index
|
||||
uint alignment_; //!< the required argument's alignment
|
||||
ArgumentType dataType_; //!< data type of the argument
|
||||
union {
|
||||
struct {
|
||||
uint uavBuf_ : 1; //!< UAV memory, no global heap
|
||||
uint realloc_ : 1; //!< argument has to be reallocatedin the global heap
|
||||
uint readOnly_ : 1; //!< Read only memory object
|
||||
uint writeOnly_ : 1; //!< Write only memory object
|
||||
uint readWrite_ : 1; //!< Read/Write memory object
|
||||
};
|
||||
uint value_;
|
||||
} memory_;
|
||||
|
||||
std::string typeName_; //!< argument's type name
|
||||
uint typeQualifier_; //!< argument's type qualifier
|
||||
|
||||
//! Default constructor for the kernel argument
|
||||
KernelArg();
|
||||
|
||||
//! Copy constructor for the kernel argument
|
||||
KernelArg(const KernelArg& data);
|
||||
|
||||
//! Overloads operator=
|
||||
KernelArg& operator=(const KernelArg& data);
|
||||
|
||||
//! Destructor of the kernel argument
|
||||
~KernelArg() { name_.clear(); }
|
||||
|
||||
/*! \brief Checks if this arguments requires a place in constant buffer
|
||||
*
|
||||
* \return True if we need CB
|
||||
*/
|
||||
bool isCbNeeded() const;
|
||||
|
||||
/*! \brief Retrieves the argument's size
|
||||
*
|
||||
* \return Size of the current argument
|
||||
*/
|
||||
size_t size(
|
||||
bool gpuLayer //!< True if we want the argument's size for the GPU layer
|
||||
) const;
|
||||
|
||||
/*! \brief Retrieves the argument's type for the abstraction layer
|
||||
*
|
||||
* \return The argument's type in the abstraction layer format
|
||||
*/
|
||||
clk_value_type_t type() const;
|
||||
|
||||
/*! \brief Retrieves the argument's address qualifier for the abstraction layer
|
||||
*
|
||||
* \return The argument's address qualifier in the abstraction layer format
|
||||
*/
|
||||
cl_kernel_arg_address_qualifier addressQualifier() const;
|
||||
|
||||
/*! \brief Retrieves the argument's access qualifier for the abstraction layer
|
||||
*
|
||||
* \return The argument's access qualifier in the abstraction layer format
|
||||
*/
|
||||
cl_kernel_arg_access_qualifier accessQualifier() const;
|
||||
|
||||
/*! \brief Retrieves the argument's type name for the abstraction layer
|
||||
*
|
||||
* \return The argument's type name
|
||||
*/
|
||||
const char* typeName() const { return typeName_.c_str(); }
|
||||
|
||||
/*! \brief Retrieves the argument's type qualifier for the abstraction layer
|
||||
*
|
||||
* \return The argument's type qualifier
|
||||
*/
|
||||
cl_kernel_arg_type_qualifier typeQualifier() const
|
||||
{
|
||||
switch (type_) {
|
||||
case PointerConst:
|
||||
case PointerHwConst:
|
||||
return static_cast<cl_kernel_arg_type_qualifier>(typeQualifier_ |
|
||||
CL_KERNEL_ARG_TYPE_CONST);
|
||||
default:
|
||||
return static_cast<cl_kernel_arg_type_qualifier>(typeQualifier_);
|
||||
}
|
||||
}
|
||||
|
||||
//! Special case for vectors with component size <= 16bit
|
||||
const static uint VectorSizeLimit = 4;
|
||||
size_t specialVector() const;
|
||||
};
|
||||
|
||||
struct DataTypeConst
|
||||
{
|
||||
const char* tagName_; //!< data type's name
|
||||
KernelArg::ArgumentType type_; //!< data type
|
||||
};
|
||||
|
||||
//! Metadata description for parsing
|
||||
struct MetaDataConst
|
||||
{
|
||||
const char* typeName_; //!< parameters name
|
||||
KernelArg::ArgumentType type_; //!< type of argument
|
||||
struct
|
||||
{
|
||||
uint size_ : 1; //!< number of arguments
|
||||
uint name_ : 1; //!< argument's name
|
||||
uint resType_: 1; //!< argument's type
|
||||
uint cbIdx_ : 1; //!< resource index CB, sampler or image
|
||||
uint cbPos_ : 1; //!< dword address in CB for the argument
|
||||
uint buf_ : 1; //!< buffer tag
|
||||
uint reserved: 26; //!< reserved
|
||||
};
|
||||
};
|
||||
|
||||
const uint DescTotal = 15;
|
||||
const uint BasicTypeTotal = 14;
|
||||
const uint ArgStateTotal = DescTotal + BasicTypeTotal;
|
||||
|
||||
//! The constant array that describes different metadata properties
|
||||
extern const MetaDataConst ArgState[ArgStateTotal];
|
||||
|
||||
extern const DataTypeConst DataType[];
|
||||
|
||||
extern const uint DataTypeTotal;
|
||||
|
||||
// Forward declaration
|
||||
class Program;
|
||||
class NullProgram;
|
||||
|
||||
class CalImageReference : public amd::ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
CalImageReference(CALimage calImage): image_(calImage) {}
|
||||
|
||||
//! Get CAL image
|
||||
CALimage calImage() const { return image_; }
|
||||
|
||||
protected:
|
||||
//! Default destructor
|
||||
~CalImageReference();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
CalImageReference(const CalImageReference&);
|
||||
|
||||
//! Disable operator=
|
||||
CalImageReference& operator=(const CalImageReference&);
|
||||
|
||||
CALimage image_; //!< CAL kernel image
|
||||
};
|
||||
|
||||
//! \class GPU NullKernel - Kernel for offline device
|
||||
class NullKernel : public device::Kernel
|
||||
{
|
||||
public:
|
||||
typedef std::vector<KernelArg*> arguments_t;
|
||||
|
||||
const static uint UavIdUndefined = 0xffff;
|
||||
|
||||
enum Flags {
|
||||
LimitWorkgroup = 1 << 0, //!< Limits the workgroup size
|
||||
PrintfOutput = 1 << 1, //!< Kernel has printf output
|
||||
PrivateFixed = 1 << 2, //!< Kernel has printf output
|
||||
ABI64bit = 1 << 3, //!< Kernel has 64 bit ABI
|
||||
Unused0 = 1 << 4, //!< Unused
|
||||
Unused1 = 1 << 5, //!< Unused
|
||||
ImageEnable = 1 << 6, //!< Kernel uses images
|
||||
ImageWrite = 1 << 7, //!< Kernel writes images
|
||||
};
|
||||
|
||||
//! \enum Resource type for binding
|
||||
enum ResourceType
|
||||
{
|
||||
Undefined = 0x00000000, //!< resource type will be detected
|
||||
ConstantBuffer = 0x00000001, //!< resource is a constant buffer
|
||||
GlobalBuffer = 0x00000002, //!< resource is a global buffer
|
||||
GlobalBufferArena = 0x00000003, //!< resource is a global buffer
|
||||
ArgumentHeapBuffer = 0x00000004, //!< resource is an argument buffer
|
||||
ArgumentBuffer = 0x00000005, //!< resource is an argument buffer
|
||||
ArgumentImageRead = 0x00000006, //!< resource is an argument image read
|
||||
ArgumentImageWrite = 0x00000007, //!< resource is an argument image write
|
||||
ArgumentConstBuffer = 0x00000008, //!< resource is an argument const buffer
|
||||
ArgumentCounter = 0x00000009, //!< resource is a global counter
|
||||
ArgumentUavID = 0x0000000a, //!< resource is a dummy ID read
|
||||
ArgumentCbID = 0x0000000b, //!< resource is a constant buffer
|
||||
ArgumentPrintfID = 0x0000000c, //!< resource is a printf buffer
|
||||
};
|
||||
|
||||
//! GPU kernel constructor
|
||||
NullKernel(
|
||||
const std::string& name, //!< The kernel's name
|
||||
const NullDevice& gpuNullDev, //!< GPU device object
|
||||
const NullProgram& nullProg //!< Reference to the program
|
||||
);
|
||||
|
||||
virtual ~NullKernel();
|
||||
|
||||
/*! \brief Creates a GPU kernel in CAL
|
||||
*
|
||||
* \return True if we successfully created a kernel in CAL
|
||||
*/
|
||||
bool create(
|
||||
const std::string& code, //!< IL source code
|
||||
const std::string& metadata, //!< the kernel metadata structure
|
||||
const void* binaryCode = NULL, //!< binary machine code for CAL
|
||||
size_t binarySize = 0 //!< the machine code size
|
||||
);
|
||||
|
||||
//! Returns CAL function descriptor
|
||||
CALimage calImage() const { return calRef_->calImage(); }
|
||||
|
||||
//! Returns TRUE if we successfully retrieved the binary from CAL
|
||||
bool getCalBinary(
|
||||
void* binary, //!< ISA binary code
|
||||
size_t size //!< ISA binary size
|
||||
) const;
|
||||
|
||||
//! Returns CAL image size
|
||||
size_t getCalBinarySize() const;
|
||||
|
||||
//! Returns GPU device object, associated with this kernel
|
||||
const NullDevice& nullDev() const { return gpuDev_; }
|
||||
|
||||
//! Returns GPU device object, associated with this kernel
|
||||
const NullProgram& nullProg() const { return prog_; }
|
||||
|
||||
//! Returns the kernel's build log
|
||||
const std::string& buildLog() const { return buildLog_; }
|
||||
|
||||
//! Returns the kernel's build error
|
||||
const cl_int buildError() const { return buildError_; }
|
||||
|
||||
//! Returns the kernel's flags
|
||||
uint flags() const { return flags_; }
|
||||
|
||||
//! Returns TRUE if ABI is for 64 bits
|
||||
bool abi64Bit() const { return (flags_ & ABI64bit) ? true : false; }
|
||||
|
||||
//! Returns the total number of all arguments
|
||||
size_t argSize() const { return arguments_.size(); }
|
||||
|
||||
//! Returns instruction count of the current kernel
|
||||
uint instructionCnt() const { return instructionCnt_; }
|
||||
|
||||
protected:
|
||||
//! Returns TRUE if memory should be reallocated, returns FALSE always for NullDevice
|
||||
virtual bool isRealloc() const { return false; }
|
||||
|
||||
/*! \brief Parses the metadata structure for the kernel,
|
||||
* provided by the OpenCL compiler
|
||||
*
|
||||
* \return True if we succefully parsed all arguments
|
||||
*/
|
||||
bool parseArguments(
|
||||
const std::string& metaData, //!< the program for parsing
|
||||
uint* uavRefCount //!< an array of reference counters for used UAVs
|
||||
);
|
||||
|
||||
//! Returns the argument for the specified index
|
||||
const KernelArg* argument(uint idx) const { return arguments_[idx]; }
|
||||
|
||||
//! Adds the kernel argument into the list
|
||||
void addArgument(KernelArg* arg) { arguments_.push_back(arg); }
|
||||
|
||||
//! Returns the argument for the specified sampler's index
|
||||
const KernelArg* sampler(uint idx) const { return intSamplers_[idx]; }
|
||||
|
||||
//! Returns the total number of all internal samplers
|
||||
size_t samplerSize() const { return intSamplers_.size(); }
|
||||
|
||||
//! Adds the kernel sampler into the sampler's list
|
||||
void addSampler(KernelArg* arg) { intSamplers_.push_back(arg); }
|
||||
|
||||
//! Returns UAV raw index for this kernel
|
||||
uint uavRaw() const { return uavRaw_; }
|
||||
|
||||
//! Returns UAV arena index for this kernel
|
||||
uint uavArena() const { return uavArena_; }
|
||||
|
||||
std::string buildLog_; //!< Kernel's build log
|
||||
cl_int buildError_; //!< Kernel's build error
|
||||
std::string ilSource_; //!< IL source code of this kernel
|
||||
|
||||
const NullDevice& gpuDev_; //!< GPU device object
|
||||
const NullProgram& prog_; //!< Reference to the parent program
|
||||
|
||||
CalImageReference* calRef_; //!< CAL image reference for this kernel
|
||||
bool internal_; //!< Runtime internal ker
|
||||
|
||||
uint flags_; //!< kernel object flags
|
||||
arguments_t arguments_; //!< kernel arguments for the execution
|
||||
arguments_t intSamplers_; //!< predefined intenal kernel samplers
|
||||
|
||||
size_t* cbSizes_; //!< real constant buffer sizes for this kernel
|
||||
uint numCb_; //!< total number of constant buffers
|
||||
|
||||
uint uavRaw_; //!< UAV used for RAW access
|
||||
uint uavArena_; //!< UAV used for arena access
|
||||
|
||||
bool rwAttributes_; //!< backend provides RW attributes for arguments
|
||||
|
||||
uint instructionCnt_;//!< Instruction count
|
||||
|
||||
uint cbId_; //!< UAV used for constant buffer access
|
||||
uint printfId_; //!< UAV used for printf buffer access
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
NullKernel(const NullKernel&);
|
||||
|
||||
//! Disable operator=
|
||||
NullKernel& operator=(const NullKernel&);
|
||||
|
||||
//! Creates a filename for ISA/IL dumps
|
||||
std::string mkDumpName(
|
||||
const char* extension //!< File extension to append
|
||||
) const;
|
||||
|
||||
bool createMultiBinary(
|
||||
uint* imageSize, //!< Multibinary image size
|
||||
void** image, //!< Multibinary image
|
||||
const void* isa //!< Kernel HW info
|
||||
);
|
||||
|
||||
//! SI HW specific setup for kernels
|
||||
bool siCreateHwInfo(
|
||||
const void* shader, //!< HW info shader
|
||||
AMUabiAddEncoding& encoding //!< ABI encoding structure
|
||||
);
|
||||
|
||||
//! r800 HW specific setup for kernels
|
||||
bool r800CreateHwInfo(
|
||||
const void* shader, //!< HW info shader
|
||||
AMUabiAddEncoding& encoding //!< ABI encoding structure
|
||||
);
|
||||
};
|
||||
|
||||
//! \class GPU kernel
|
||||
class Kernel : public NullKernel
|
||||
{
|
||||
public:
|
||||
struct InitData {
|
||||
uint privateSize_; //!< Private ring initial size
|
||||
uint localSize_; //!< Local ring initial size
|
||||
uint hwPrivateSize_; //!< HW private ring initial size
|
||||
uint hwLocalSize_; //!< HW local ring initial size
|
||||
uint flags_; //!< Kernel initialization flags
|
||||
};
|
||||
|
||||
//! GPU kernel constructor
|
||||
Kernel(
|
||||
const std::string& name, //!< The kernel's name
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
const Program& prog, //!< Reference to the program
|
||||
const InitData* initData_ //!< Initialization data
|
||||
);
|
||||
|
||||
//! GPU kernel destructor
|
||||
virtual ~Kernel();
|
||||
|
||||
/*! \brief Creates a GPU kernel in CAL
|
||||
*
|
||||
* \return True if we successfully created a kernel in CAL
|
||||
*/
|
||||
bool create(
|
||||
const std::string& code, //!< IL source code
|
||||
const std::string& metadata, //!< the kernel metadata structure
|
||||
const void* binaryCode = NULL, //!< binary machine code for CAL
|
||||
size_t binarySize = 0 //!< the machine code size
|
||||
);
|
||||
|
||||
//! Validates memory argument
|
||||
virtual bool validateMemory(
|
||||
uint idx, //!< Argument's index
|
||||
amd::Memory* amdMem //!< AMD memory object for validation
|
||||
) const ;
|
||||
|
||||
//! Initializes the CAL program grid for the kernel execution
|
||||
void setupProgramGrid(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
size_t workDim, //!< work dimension
|
||||
const amd::NDRange& glbWorkOffset, //!< global work offset
|
||||
const amd::NDRange& gblWorkSize, //!< global work size
|
||||
amd::NDRange& lclWorkSize, //!< local work size
|
||||
const amd::NDRange& groupOffset, //!< group offsets
|
||||
const amd::NDRange& glbWorkOffsetOrg,
|
||||
const amd::NDRange& glbWorkSizeOrg //!< original global work size
|
||||
) const;
|
||||
|
||||
/*! \brief Detects if runtime has to disable cache optimization and
|
||||
* recompiles the kernel
|
||||
*
|
||||
* \return True if aliases were detected in the kernel arguments
|
||||
*/
|
||||
bool processMemObjects(
|
||||
VirtualGPU& gpu, //!< Virtual GPU objects - queue
|
||||
const amd::Kernel& kernel, //!< AMD kernel object for execution
|
||||
const_address params, //!< pointer to the param's store
|
||||
bool nativeMem //!< Native memory objects
|
||||
) const;
|
||||
|
||||
/*! \brief Loads all kernel arguments, so we could run the kernel in HW.
|
||||
* This includes CB update and resource binding
|
||||
*
|
||||
* \return True if we succefully loaded the arguments
|
||||
*/
|
||||
bool loadParameters(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
const amd::Kernel& kernel, //!< AMD kernel object for execution
|
||||
const_address params, //!< pointer to the param's store
|
||||
bool nativeMem //!< Native memory objects
|
||||
) const;
|
||||
|
||||
//! Binds the constant buffers associated with the kernel
|
||||
bool bindConstantBuffers(VirtualGPU& gpu) const;
|
||||
|
||||
/*! \brief Runs the kernel on HW
|
||||
*
|
||||
* \return True if we succefully executed the kernel
|
||||
*/
|
||||
bool run(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
GpuEvent* gpuEvent, //!< Pointer to the GPU event
|
||||
bool lastRun //!< Last run in the split execution
|
||||
) const;
|
||||
|
||||
//! Help function to debug the kernel output
|
||||
void debug(
|
||||
VirtualGPU& gpu //!< virtual GPU device object
|
||||
) const;
|
||||
|
||||
//! Programs internal samplers defined inside the kernel
|
||||
bool setInternalSamplers(
|
||||
VirtualGPU& gpu //!< Virtual GPU device object
|
||||
) const;
|
||||
|
||||
//! Returns TRUE if we successfully retrieved the binary from CAL
|
||||
bool getCalBinary(
|
||||
void* binary, //!< ISA binary code
|
||||
size_t size //!< ISA binary size
|
||||
) const;
|
||||
|
||||
//! Returns CAL image size
|
||||
size_t getCalBinarySize() const;
|
||||
|
||||
//! Returns GPU device object, associated with this kernel
|
||||
const Device& dev() const;
|
||||
|
||||
//! Returns GPU device object, associated with this kernel
|
||||
const Program& prog() const;
|
||||
|
||||
//! Binds global HW constant buffers
|
||||
bool bindGlobalHwCb(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
VirtualGPU::GslKernelDesc* desc //!< Kernel descriptor
|
||||
) const;
|
||||
|
||||
protected:
|
||||
//! Initializes the kernel parameters for the abstraction layer
|
||||
bool initParameters();
|
||||
|
||||
/*! \brief Creates constant buffer resources, associated with the kernel
|
||||
*
|
||||
* \return TRUE if we succefully created constant buffers
|
||||
*/
|
||||
bool initConstBuffers();
|
||||
|
||||
//! Returns TRUE if memory should be reallocated, returns FALSE always for NullDevice
|
||||
virtual bool isRealloc() const { return !dev().heap()->isVirtual(); }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Kernel(const Kernel&);
|
||||
|
||||
//! Disable operator=
|
||||
Kernel& operator=(const Kernel&);
|
||||
|
||||
//! \enum Fixed Metadata offsets
|
||||
enum MetadataOffsets
|
||||
{
|
||||
GlobalWorkitemOffset = 0,
|
||||
LocalWorkitemOffset = 1,
|
||||
GroupsOffset = 2,
|
||||
PrivateRingOffset = 3,
|
||||
LocalRingOffset = 4,
|
||||
MathLibOffset = 5,
|
||||
GlobalWorkOffsetOffset = 6,
|
||||
GroupWorkOffsetOffset = 7,
|
||||
GlobalDataStoreOffset = 8,
|
||||
DebugOffset = 8,
|
||||
NDRangeGlobalWorkOffsetOffset = 9,
|
||||
|
||||
// The total number of constants reserved for ABI
|
||||
TotalABIVectors
|
||||
};
|
||||
|
||||
/*! \brief Sets the kernel argument
|
||||
*
|
||||
* \return True if we succefully updated the arguments
|
||||
*/
|
||||
bool setArgument(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
uint idx, //!< the argument index
|
||||
const void* param, //!< the arguments data
|
||||
size_t size, //!< size of the provided data
|
||||
bool nativeMem //!< Native memory objects
|
||||
) const;
|
||||
|
||||
/*! \brief Initializes local and private buffer ranges
|
||||
*
|
||||
* \return True if we succefully initialized the ranges
|
||||
*/
|
||||
bool initLocalPrivateRanges(
|
||||
VirtualGPU& gpu //!< Virtual GPU device object
|
||||
) const;
|
||||
|
||||
//! Sets local and private buffer ranges
|
||||
void setLocalPrivateRanges(
|
||||
VirtualGPU& gpu //!< Virtual GPU device object
|
||||
) const;
|
||||
|
||||
//! Sets the sampler's parameters for the image look-up
|
||||
void setSampler(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
uint32_t state, //!< sampler state
|
||||
uint physUnit //!< sampler's number
|
||||
) const;
|
||||
|
||||
/*! \brief Binds resource
|
||||
*
|
||||
* \return True if we succefully created constant buffers
|
||||
*/
|
||||
bool bindResource(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
const Resource& resource, //!< resource for binding
|
||||
uint paramIdx, //!< index of the parameter
|
||||
ResourceType type, //!< resource type
|
||||
uint physUnit, //!< PhysUnit
|
||||
Memory* memory = NULL, //!< GPU layer memory object
|
||||
size_t offset = 0
|
||||
) const;
|
||||
|
||||
//! Unbinds all resources for the kernel
|
||||
void unbindResources(
|
||||
VirtualGPU& gpu, //!< virtual GPU device object
|
||||
GpuEvent gpuEvent, //!< GPU event that will be associated with the resources
|
||||
bool lastRun //!< last run in the split execution
|
||||
) const;
|
||||
|
||||
//! Returns true if arena setup was successful
|
||||
bool setupArenaAliases(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
const Resource& resource //!< Resource for aliases setup
|
||||
) const;
|
||||
|
||||
//! Copies image constants to the constant buffer
|
||||
void copyImageConstants(
|
||||
const amd::Image* amdImage, //!< Abstraction layer image object
|
||||
ImageConstants* imageData //!< Pointer in CB to the image constants
|
||||
) const;
|
||||
|
||||
//! Finds local workgroup size
|
||||
void findLocalWorkSize(
|
||||
size_t workDim, //!< Work dimension
|
||||
const amd::NDRange& gblWorkSize,//!< Global work size
|
||||
amd::NDRange& lclWorkSize //!< Local work size
|
||||
) const;
|
||||
|
||||
uint hwPrivateSize_; //!< initial HW private size
|
||||
uint hwLocalSize_; //!< initial HW local size
|
||||
|
||||
//! @todo remove the blit kernel hack
|
||||
bool blitKernelHack_; //!< No VM hack for kernel blit
|
||||
};
|
||||
|
||||
enum HSAIL_ADDRESS_QUALIFIER{
|
||||
HSAIL_ADDRESS_ERROR = 0,
|
||||
HSAIL_ADDRESS_GLOBAL,
|
||||
HSAIL_ADDRESS_LOCAL,
|
||||
HSAIL_MAX_ADDRESS_QUALIFIERS
|
||||
} ;
|
||||
|
||||
enum HSAIL_ARG_TYPE{
|
||||
HSAIL_ARGTYPE_ERROR = 0,
|
||||
HSAIL_ARGTYPE_POINTER,
|
||||
HSAIL_ARGTYPE_VALUE,
|
||||
HSAIL_ARGTYPE_IMAGE,
|
||||
HSAIL_ARGTYPE_SAMPLER,
|
||||
HSAIL_ARGTYPE_QUEUE,
|
||||
HSAIL_ARGMAX_ARG_TYPES
|
||||
};
|
||||
|
||||
enum HSAIL_DATA_TYPE{
|
||||
HSAIL_DATATYPE_ERROR = 0,
|
||||
HSAIL_DATATYPE_B1,
|
||||
HSAIL_DATATYPE_B8,
|
||||
HSAIL_DATATYPE_B16,
|
||||
HSAIL_DATATYPE_B32,
|
||||
HSAIL_DATATYPE_B64,
|
||||
HSAIL_DATATYPE_S8,
|
||||
HSAIL_DATATYPE_S16,
|
||||
HSAIL_DATATYPE_S32,
|
||||
HSAIL_DATATYPE_S64,
|
||||
HSAIL_DATATYPE_U8,
|
||||
HSAIL_DATATYPE_U16,
|
||||
HSAIL_DATATYPE_U32,
|
||||
HSAIL_DATATYPE_U64,
|
||||
HSAIL_DATATYPE_F16,
|
||||
HSAIL_DATATYPE_F32,
|
||||
HSAIL_DATATYPE_F64,
|
||||
HSAIL_DATATYPE_STRUCT,
|
||||
HSAIL_DATATYPE_OPAQUE,
|
||||
HSAIL_DATATYPE_MAX_TYPES
|
||||
};
|
||||
|
||||
|
||||
class HSAILKernel : public device::Kernel
|
||||
{
|
||||
public:
|
||||
struct Argument
|
||||
{
|
||||
std::string name_; //!< Argument's name
|
||||
std::string typeName_; //!< Argument's type name
|
||||
uint size_; //!< Size in bytes
|
||||
uint offset_; //!< Argument's offset
|
||||
uint alignment_; //!< Argument's alignment
|
||||
HSAIL_ARG_TYPE type_; //!< Type of the argument
|
||||
HSAIL_ADDRESS_QUALIFIER addrQual_; //!< Address qualifier of the argument
|
||||
HSAIL_DATA_TYPE dataType_; //!< The type of data
|
||||
uint numElem_; //!< Number of elements
|
||||
};
|
||||
|
||||
// Global offsets located in the first 3 elements
|
||||
static const uint ExtraArguments = 6;
|
||||
|
||||
HSAILKernel(std::string name,
|
||||
HSAILProgram* prog,
|
||||
std::string compileOptions);
|
||||
|
||||
virtual ~HSAILKernel();
|
||||
|
||||
//! Initializes the metadata required for this kernel
|
||||
bool init();
|
||||
|
||||
//! Returns true if memory is valid for execution
|
||||
virtual bool validateMemory(uint idx, amd::Memory* amdMem) const;
|
||||
|
||||
//! Returns a pointer to the hsail argument
|
||||
const Argument* argument(size_t i) const { return arguments_[i]; }
|
||||
|
||||
//! Returns the number of hsail arguments
|
||||
size_t numArguments() const { return arguments_.size(); }
|
||||
|
||||
//! Returns GPU device object, associated with this kernel
|
||||
const Device& dev() const;
|
||||
|
||||
//! Returns HSA program associated with this kernel
|
||||
const HSAILProgram& prog() const;
|
||||
|
||||
//! Returns LDS size used in this kernel
|
||||
uint32_t ldsSize() const
|
||||
{ return cpuAqlCode_->workgroup_group_segment_byte_size; }
|
||||
|
||||
//! Returns pointer on CPU to AQL code info
|
||||
const void* cpuAqlCode() const { return cpuAqlCode_; }
|
||||
|
||||
//! Returns memory object with AQL code
|
||||
const gpu::Memory* gpuAqlCode() const { return code_; }
|
||||
|
||||
//! Returns the size of argument buffer
|
||||
size_t argsBufferSize() const
|
||||
{ return cpuAqlCode_->kernarg_segment_byte_size; }
|
||||
|
||||
//! Returns spill reg size per workitem
|
||||
int spillSegSize() const
|
||||
{ return cpuAqlCode_->workitem_private_segment_byte_size; }
|
||||
|
||||
//! Returns TRUE if kernel uses dynamic parallelism
|
||||
bool dynamicParallelism() const
|
||||
{ return (flags_.dynamicParallelism_) ? true : false; }
|
||||
|
||||
//! Finds local workgroup size
|
||||
void findLocalWorkSize(
|
||||
size_t workDim, //!< Work dimension
|
||||
const amd::NDRange& gblWorkSize,//!< Global work size
|
||||
amd::NDRange& lclWorkSize //!< Local work size
|
||||
) const;
|
||||
|
||||
//! Returns AQL packet in CPU memory
|
||||
//! if the kerenl arguments were successfully loaded, otherwise NULL
|
||||
HsaAqlDispatchPacket* loadArguments(
|
||||
VirtualGPU& gpu, //!< Running GPU context
|
||||
const amd::Kernel& kernel, //!< AMD kernel object
|
||||
const amd::NDRangeContainer& sizes, //!< NDrange container
|
||||
const_address parameters, //!< Application arguments for the kernel
|
||||
bool nativeMem, //!< Native memory objectes are passed
|
||||
uint64_t vmDefQueue, //!< GPU VM default queue pointer
|
||||
uint64_t* vmParentWrap, //!< GPU VM parent aql wrap object
|
||||
std::vector<const Resource*>& memList //!< Memory list for GSL/VidMM handles
|
||||
) const;
|
||||
|
||||
//! Returns pritnf info array
|
||||
const std::vector<PrintfInfo>& printfInfo() const { return printf_; }
|
||||
|
||||
//! Returns the kernel index in the program
|
||||
uint index() const { return index_; }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
HSAILKernel(const HSAILKernel&);
|
||||
|
||||
//! Disable operator=
|
||||
HSAILKernel& operator=(const HSAILKernel&);
|
||||
|
||||
//! Creates AQL kernel HW info
|
||||
bool aqlCreateHWInfo(
|
||||
const void* kernel, //!< Kernel's packed binary info and code
|
||||
size_t kernelSize //!< Size of the kernel's packed binary
|
||||
);
|
||||
|
||||
//! Initializes arguments_ and the abstraction layer kernel parameters
|
||||
void initArgList(
|
||||
const aclArgData* aclArg //!< List of ACL arguments
|
||||
);
|
||||
|
||||
//! Initializes Hsail Argument metadata and info
|
||||
void initHsailArgs(
|
||||
const aclArgData* aclArg //!< List of ACL arguments
|
||||
);
|
||||
|
||||
//! Initializes Hsail Printf metadata and info
|
||||
void initPrintf(
|
||||
const aclPrintfFmt* aclPrintf //!< List of ACL printfs
|
||||
);
|
||||
|
||||
std::vector<Argument*> arguments_; //!< Vector list of HSAIL Arguments
|
||||
std::string compileOptions_; //!< compile used for finalizing this kernel
|
||||
amd_kernel_code_t* cpuAqlCode_; //!< AQL kernel code on CPU
|
||||
const NullDevice& dev_; //!< GPU device object
|
||||
const HSAILProgram& prog_; //!< Reference to the parent program
|
||||
std::vector<PrintfInfo> printf_; //!< Format strings for GPU printf support
|
||||
uint index_; //!< Kernel index in the program
|
||||
|
||||
gpu::Memory* code_; //!< Memory object with ISA code
|
||||
char* hwMetaData_; //!< SI metadata
|
||||
|
||||
union Flags {
|
||||
struct {
|
||||
uint imageEna_: 1; //!< Kernel uses images
|
||||
uint imageWriteEna_: 1; //!< Kernel uses image writes
|
||||
uint dynamicParallelism_: 1; //!< Dynamic parallelism enabled
|
||||
};
|
||||
uint value_;
|
||||
Flags(): value_(0) {}
|
||||
} flags_;
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUKERNEL_HPP_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,305 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUMEMORY_HPP_
|
||||
#define GPUMEMORY_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "thread/atomic.hpp"
|
||||
#include "device/gpu/gpuresource.hpp"
|
||||
#include "device/gpu/gpuheap.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
#include <map>
|
||||
|
||||
/*! \addtogroup GPU
|
||||
* @{
|
||||
*/
|
||||
namespace device {
|
||||
class Memory;
|
||||
}
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class Heap;
|
||||
class Resource;
|
||||
class Memory;
|
||||
class VirtualGPU;
|
||||
class HeapBlock;
|
||||
|
||||
//! GPU memory object.
|
||||
// Wrapper that can contain a heap block or an interop buffer/image.
|
||||
class Memory: public device::Memory, public Resource
|
||||
{
|
||||
public:
|
||||
enum InteropType {
|
||||
InteropNone = 0, //!< None interop memory
|
||||
InteropHwEmulation = 1, //!< Uses HW emulaiton with calMemCopy
|
||||
InteropDirectAccess = 2 //!< Uses direct access to the interop surface
|
||||
};
|
||||
|
||||
//! Constructor (with owner)
|
||||
Memory(
|
||||
const Device& gpuDev,
|
||||
amd::Memory& owner,
|
||||
HeapBlock* hb,
|
||||
size_t size = 0);
|
||||
|
||||
//! Constructor (nonfat version for local scratch mem use)
|
||||
Memory(
|
||||
const Device& gpuDev,
|
||||
HeapBlock& hb);
|
||||
|
||||
//! Constructor (nonfat version for local scratch mem use without heap block)
|
||||
Memory(
|
||||
const Device& gpuDev,
|
||||
size_t size);
|
||||
|
||||
//! Constructor memory for buffer (without global heap allocaton)
|
||||
Memory(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
size_t width, //!< Memory width
|
||||
cmSurfFmt format //!< CAL format
|
||||
);
|
||||
|
||||
//! Constructor memory for buffer (without global heap allocaton)
|
||||
Memory(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
size_t size, //!< Memory object size
|
||||
size_t width, //!< Memory width
|
||||
cmSurfFmt format //!< CAL format
|
||||
);
|
||||
|
||||
//! Constructor memory for images (without global heap allocaton)
|
||||
Memory(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
size_t width, //!< Allocated memory width
|
||||
size_t height, //!< Allocated memory height
|
||||
size_t depth, //!< Allocated memory depth
|
||||
cmSurfFmt format, //!< Memory format
|
||||
gslChannelOrder chOrder, //!< Channel order
|
||||
cl_mem_object_type imageType //!< CL image type
|
||||
);
|
||||
|
||||
//! Constructor memory for images (without global heap allocaton)
|
||||
Memory(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
size_t size, //!< Memory object size
|
||||
size_t width, //!< Allocated memory width
|
||||
size_t height, //!< Allocated memory height
|
||||
size_t depth, //!< Allocated memory depth
|
||||
cmSurfFmt format, //!< Memory format
|
||||
gslChannelOrder chOrder, //!< Channel order
|
||||
cl_mem_object_type imageType //!< CL image type
|
||||
);
|
||||
|
||||
//! Default destructor
|
||||
~Memory();
|
||||
|
||||
//! Reallocates the memory object in the new heap block
|
||||
bool reallocate(
|
||||
HeapBlock* hb, //! The new heap block for this memory object
|
||||
const Resource* parent //! Parent resource for view reallocaiton
|
||||
);
|
||||
|
||||
//! Creates the interop memory
|
||||
bool createInterop(
|
||||
InteropType type //!< The interop type
|
||||
);
|
||||
|
||||
//! Overloads the resource create method
|
||||
virtual bool create(
|
||||
Resource::MemoryType memType, //!< Memory type
|
||||
Resource::CreateParams* params = NULL //!< Prameters for create
|
||||
);
|
||||
|
||||
//! Allocate memory for API-level maps
|
||||
virtual void* allocMapTarget(
|
||||
const amd::Coord3D& origin, //!< The map location in memory
|
||||
const amd::Coord3D& region, //!< The map region in memory
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the mapped memory
|
||||
size_t* slicePitch = NULL //!< Slice for the mapped memory
|
||||
);
|
||||
|
||||
//! Pins system memory associated with this memory object
|
||||
virtual bool pinSystemMemory(
|
||||
void* hostPtr, //!< System memory address
|
||||
size_t size //!< Size of allocated system memory
|
||||
);
|
||||
|
||||
//! Releases indirect map surface
|
||||
virtual void releaseIndirectMap() { decIndMapCount(); }
|
||||
|
||||
//! Map the device memory to CPU visible
|
||||
virtual void* cpuMap(
|
||||
device::VirtualDevice& vDev,//!< Virtual device for map operaiton
|
||||
uint flags = 0, //!< flags for the map operation
|
||||
// Optimization for multilayer map/unmap
|
||||
uint startLayer = 0, //!< Start layer for multilayer map
|
||||
uint numLayers = 0, //!< End layer for multilayer map
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the device memory
|
||||
size_t* slicePitch = NULL //!< Slice pitch for the device memory
|
||||
);
|
||||
|
||||
//! Unmap the device memory
|
||||
virtual void cpuUnmap(
|
||||
device::VirtualDevice& vDev //!< Virtual device for unmap operaiton
|
||||
);
|
||||
|
||||
//! Updates device memory from the owner's host allocation
|
||||
void syncCacheFromHost(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
//! Synchronization flags
|
||||
device::Memory::SyncFlags syncFlags = device::Memory::SyncFlags()
|
||||
);
|
||||
|
||||
//! Updates the owner's host allocation from device memory
|
||||
virtual void syncHostFromCache(
|
||||
//! Synchronization flags
|
||||
device::Memory::SyncFlags syncFlags = device::Memory::SyncFlags()
|
||||
);
|
||||
|
||||
//! Creates a view from current resource
|
||||
virtual Memory* createBufferView(
|
||||
amd::Memory& subBufferOwner //!< The abstraction layer subbuf owner
|
||||
);
|
||||
|
||||
//! Allocates host memory for synchronization with MGPU context
|
||||
void mgpuCacheWriteBack();
|
||||
|
||||
//! Transfers objects data to the destination object
|
||||
bool moveTo(Memory& dst);
|
||||
|
||||
//! Accessors for indirect map memory object
|
||||
Memory* mapMemory() const;
|
||||
|
||||
//! Returns the interop memory for this memory object
|
||||
Memory* interop() const { return interopMemory_; }
|
||||
|
||||
//! Gets interop type for this memory object
|
||||
InteropType interopType() const { return interopType_; }
|
||||
|
||||
//! Sets interop type for this memory object
|
||||
void setInteropType(InteropType type) { interopType_ = type; }
|
||||
|
||||
//! Returns the HeapBlock pointer
|
||||
const HeapBlock* hb() const { return hb_; }
|
||||
|
||||
//! Set the owner
|
||||
void setOwner(amd::Memory* owner) { owner_ = owner; }
|
||||
|
||||
// Decompress GL depth-stencil/MSAA resources for CL access
|
||||
// Invalidates any FBOs the resource may be bound to, otherwise the GL driver may crash.
|
||||
virtual bool processGLResource(GLResourceOP operation);
|
||||
|
||||
//! Returns the interop resource for this memory object
|
||||
const Memory* parent() const { return parent_; }
|
||||
|
||||
protected:
|
||||
//! Decrement map count
|
||||
void decIndMapCount();
|
||||
|
||||
//! Initialize the object members
|
||||
void init();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Memory(const Memory&);
|
||||
|
||||
//! Disable operator=
|
||||
Memory& operator=(const Memory&);
|
||||
|
||||
InteropType interopType_; //!< Interop type
|
||||
Memory* interopMemory_; //!< interop memory
|
||||
|
||||
HeapBlock* hb_; //!< Heap Block, or NULL if not in-heap memory
|
||||
Memory* pinnedMemory_; //!< Memory used as pinned system memory
|
||||
const Memory* parent_; //!< Parent memory object
|
||||
};
|
||||
|
||||
class Buffer: public gpu::Memory
|
||||
{
|
||||
public:
|
||||
//! Buffer constructor
|
||||
Buffer(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
size_t size //!< Buffer size
|
||||
)
|
||||
: gpu::Memory(gpuDev, owner,
|
||||
amd::alignUp(size, ElementSize) / ElementSize, ElementType)
|
||||
{}
|
||||
|
||||
//! Creates a view from current resource
|
||||
virtual Memory* createBufferView(
|
||||
amd::Memory& subBufferOwner //!< The abstraction layer subbuf owner
|
||||
) const;
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Buffer(const Buffer&);
|
||||
|
||||
//! Disable operator=
|
||||
Buffer& operator=(const Buffer&);
|
||||
|
||||
//! The size of buffer element in bytes
|
||||
static const size_t ElementSize = 4;
|
||||
|
||||
//! The type of buffer element
|
||||
static const cmSurfFmt ElementType = CM_SURF_FMT_R32I;
|
||||
};
|
||||
|
||||
class Image: public gpu::Memory
|
||||
{
|
||||
public:
|
||||
//! Image constructor
|
||||
Image(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
amd::Memory& owner, //!< Abstraction layer memory object
|
||||
size_t width, //!< Allocated memory width
|
||||
size_t height, //!< Allocated memory height
|
||||
size_t depth, //!< Allocated memory depth
|
||||
cmSurfFmt format, //!< Memory format
|
||||
gslChannelOrder chOrder, //!< Channel order
|
||||
cl_mem_object_type imageType //!< CL image type
|
||||
)
|
||||
: gpu::Memory(gpuDev, owner, width, height, depth, format, chOrder, imageType)
|
||||
{}
|
||||
|
||||
//! Image constructor
|
||||
Image(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
size_t size, //!< Memory size
|
||||
size_t width, //!< Allocated memory width
|
||||
size_t height, //!< Allocated memory height
|
||||
size_t depth, //!< Allocated memory depth
|
||||
cmSurfFmt format, //!< Memory format
|
||||
gslChannelOrder chOrder, //!< Channel order
|
||||
cl_mem_object_type imageType //!< CL image type
|
||||
)
|
||||
: gpu::Memory(gpuDev, size, width, height, depth, format, chOrder, imageType)
|
||||
{}
|
||||
|
||||
//! Allocate memory for API-level maps
|
||||
virtual void* allocMapTarget(
|
||||
const amd::Coord3D& origin, //!< The map location in memory
|
||||
const amd::Coord3D& region, //!< The map region in memory
|
||||
size_t* rowPitch = NULL, //!< Row pitch for the mapped memory
|
||||
size_t* slicePitch = NULL //!< Slice for the mapped memory
|
||||
);
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Image(const Image&);
|
||||
|
||||
//! Disable operator=
|
||||
Image& operator=(const Image&);
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPUMEMORY_HPP_
|
||||
@@ -0,0 +1,722 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "top.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpumemory.hpp"
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
#include "device/gpu/gpuprogram.hpp"
|
||||
#include "device/gpu/gpuprintf.hpp"
|
||||
#include <cstdio>
|
||||
#include <math.h>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
PrintfDbg::PrintfDbg(Device& device, FILE* file)
|
||||
: dbgBuffer_(NULL)
|
||||
, dbgFile_(file)
|
||||
, gpuDevice_(device)
|
||||
, wiDbgSize_(0)
|
||||
, initCntValue_(device, 1, CM_SURF_FMT_R32I)
|
||||
{
|
||||
}
|
||||
|
||||
PrintfDbg::~PrintfDbg()
|
||||
{
|
||||
delete dbgBuffer_;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::create()
|
||||
{
|
||||
// Create a resource for the init count value
|
||||
if (initCntValue_.create(Resource::Remote)) {
|
||||
uint32_t* value = reinterpret_cast<uint32_t*>(initCntValue_.map(NULL));
|
||||
// The counter starts from 1
|
||||
if (NULL != value) {
|
||||
*value = 1;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
initCntValue_.unmap(NULL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::init(
|
||||
VirtualGPU& gpu,
|
||||
bool printfEnabled,
|
||||
const amd::NDRange& size)
|
||||
{
|
||||
// Set up debug output buffer (if printf active)
|
||||
if (printfEnabled) {
|
||||
if (!allocate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure that the size isn't bigger than the reported max
|
||||
if (size.product() <= dev().settings().maxWorkGroupSize_) {
|
||||
size_t wiDbgSizeTmp;
|
||||
|
||||
// Calculate the debug buffer size per workitem
|
||||
wiDbgSizeTmp = std::min(dbgBuffer_->size() / size.product(),
|
||||
dev().xferRead().bufSize());
|
||||
|
||||
// Make sure the size is DWORD aligned
|
||||
wiDbgSizeTmp = amd::alignDown(wiDbgSizeTmp, sizeof(uint32_t));
|
||||
|
||||
// If the new size is different, then clear the initial values
|
||||
if (wiDbgSize_ != wiDbgSizeTmp) {
|
||||
wiDbgSize_ = wiDbgSizeTmp;
|
||||
if (!clearWorkitems(gpu, 0, size.product())) {
|
||||
wiDbgSize_ = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::output(
|
||||
VirtualGPU& gpu,
|
||||
bool printfEnabled,
|
||||
const amd::NDRange& size,
|
||||
const std::vector<PrintfInfo>& printfInfo)
|
||||
{
|
||||
// Are we expected to generate debug output?
|
||||
if (printfEnabled) {
|
||||
uint32_t* workitemData;
|
||||
size_t i, j, k, z;
|
||||
bool realloc = false;
|
||||
|
||||
// Wait for kernel execution
|
||||
gpu.waitAllEngines();
|
||||
|
||||
size_t zdim = 1;
|
||||
size_t ydim = 1;
|
||||
size_t xdim = 1;
|
||||
|
||||
switch (size.dimensions()) {
|
||||
case 3:
|
||||
zdim = size[2];
|
||||
// Fall through ...
|
||||
case 2:
|
||||
ydim = size[1];
|
||||
// Fall through ...
|
||||
case 1:
|
||||
xdim = size[0];
|
||||
// Fall through ...
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (k = 0; k < zdim; ++k) {
|
||||
for (j = 0; j < ydim; ++j) {
|
||||
for (i = 0; i < xdim; ++i) {
|
||||
size_t idx = (xdim * (ydim * k + j) + i);
|
||||
workitemData = mapWorkitem(gpu, idx, &realloc);
|
||||
|
||||
if (NULL != workitemData) {
|
||||
uint32_t wp = workitemData[0]; // write pointer (i.e. first unwritten element)
|
||||
// Walk through each PrintfDbg entry
|
||||
for (z = 1; (z < (wiDbgSize() / sizeof(uint32_t))) && (z < wp); ) {
|
||||
if (printfInfo.size() < workitemData[z]) {
|
||||
LogError("The format string wasn't reported");
|
||||
return false;
|
||||
}
|
||||
// Get the PrintfDbg info
|
||||
const PrintfInfo& info = printfInfo[workitemData[z++]];
|
||||
// There's something in this buffer
|
||||
outputDbgBuffer(info, workitemData, z);
|
||||
}
|
||||
}
|
||||
unmapWorkitem(gpu, workitemData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reallocate debug buffer if necessary
|
||||
if (!allocate(realloc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PrintfDbg::bufOffset() const
|
||||
{
|
||||
return dbgBuffer_->hbOffset();
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::allocate(bool realloc)
|
||||
{
|
||||
if (NULL == dbgBuffer_) {
|
||||
dbgBuffer_ = dev().createScratchBuffer(dev().info().printfBufferSize_);
|
||||
}
|
||||
else if (realloc) {
|
||||
LogWarning("Debug buffer reallocation!");
|
||||
// Double the buffer size if it's not big enough
|
||||
size_t size = dbgBuffer_->size();
|
||||
delete dbgBuffer_;
|
||||
dbgBuffer_ = dev().createScratchBuffer(size << 1);
|
||||
}
|
||||
|
||||
return (NULL != dbgBuffer_) ? true : false;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::checkFloat(const std::string& fmt) const
|
||||
{
|
||||
switch (fmt[fmt.size() - 1]) {
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'a':
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::checkString(const std::string& fmt) const
|
||||
{
|
||||
if (fmt[fmt.size() - 1] == 's')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
PrintfDbg::checkVectorSpecifier(
|
||||
const std::string& fmt,
|
||||
size_t startPos,
|
||||
size_t& curPos) const
|
||||
{
|
||||
int vectorSize = 0;
|
||||
size_t pos = curPos;
|
||||
size_t size = curPos - startPos;
|
||||
|
||||
if (size >= 3) {
|
||||
size = 0;
|
||||
//no modifiers
|
||||
if (fmt[curPos - 3] == 'v') {
|
||||
size = 2;
|
||||
}
|
||||
//the modifiers are "h" or "l"
|
||||
else if (fmt[curPos - 4] == 'v') {
|
||||
size = 3;
|
||||
}
|
||||
//the modifier is "hh"
|
||||
else if ((curPos >= 5) && (fmt[curPos - 5] == 'v')) {
|
||||
size = 4;
|
||||
}
|
||||
if (size > 0) {
|
||||
curPos = size;
|
||||
pos -= curPos;
|
||||
|
||||
// Get vector size
|
||||
vectorSize = fmt[pos++] - '0';
|
||||
// PrintfDbg supports only 2, 3, 4, 8 and 16 wide vectors
|
||||
switch (vectorSize) {
|
||||
case 1:
|
||||
if ((fmt[pos++] - '0') == 6) {
|
||||
vectorSize = 16;
|
||||
}
|
||||
else {
|
||||
vectorSize = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
vectorSize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vectorSize;
|
||||
}
|
||||
|
||||
static const size_t ConstStr = 0xffffffff;
|
||||
static const char Separator[] = ",\0";
|
||||
|
||||
size_t
|
||||
PrintfDbg::outputArgument(
|
||||
const std::string& fmt,
|
||||
bool printFloat,
|
||||
size_t size,
|
||||
const uint32_t* argument) const
|
||||
{
|
||||
// Serialize the output to the screen
|
||||
amd::ScopedLock k(dev().lockAsyncOps());
|
||||
|
||||
size_t copiedBytes = size;
|
||||
// Print the string argument, using standard PrintfDbg()
|
||||
if (checkString(fmt.c_str())) {
|
||||
//copiedBytes should be as number of printed chars
|
||||
copiedBytes = 0;
|
||||
//(null) should be printed
|
||||
if (*argument == 0) {
|
||||
amd::Os::printf(fmt.data(),0);
|
||||
//copiedBytes = strlen("(null)")
|
||||
copiedBytes = 6;
|
||||
}
|
||||
else {
|
||||
const unsigned char* argumentStr = reinterpret_cast<const unsigned char*>(argument);
|
||||
amd::Os::printf(fmt.data(),argumentStr);
|
||||
//copiedBytes = strlen(argumentStr)
|
||||
while (argumentStr[copiedBytes++] != 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Print the argument(except for string ), using standard PrintfDbg()
|
||||
else {
|
||||
bool hlModifier = (strstr(fmt.c_str(),"hl") != NULL);
|
||||
std::string hlFmt;
|
||||
if (hlModifier) {
|
||||
hlFmt = fmt;
|
||||
hlFmt.erase(hlFmt.find_first_of("hl"),2);
|
||||
}
|
||||
switch (size) {
|
||||
case 0: {
|
||||
const char* str = reinterpret_cast<const char*>(argument);
|
||||
amd::Os::printf(fmt.data(), str);
|
||||
// Find the string length
|
||||
while (str[copiedBytes++] != 0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
amd::Os::printf(fmt.data(), *(reinterpret_cast<const unsigned char*>(argument)));
|
||||
break;
|
||||
case 2:
|
||||
case 4:
|
||||
if (printFloat) {
|
||||
static const char* fSpecifiers = "eEfgGa";
|
||||
std::string fmtF = fmt;
|
||||
size_t posS = fmtF.find_first_of("%");
|
||||
size_t posE = fmtF.find_first_of(fSpecifiers);
|
||||
if (posS != std::string::npos &&posE != std::string::npos) {
|
||||
fmtF.replace(posS+1,posE-posS,"s");
|
||||
}
|
||||
float fArg = *(reinterpret_cast<const float*>(argument));
|
||||
float fSign = copysign(1.0,fArg);
|
||||
if (isinf(fArg)&&!isnan(fArg)) {
|
||||
if(fSign < 0) {
|
||||
amd::Os::printf(fmtF.data(),"-infinity");
|
||||
}
|
||||
else {
|
||||
amd::Os::printf(fmtF.data(),"infinity");
|
||||
}
|
||||
}
|
||||
else if (isnan(fArg)) {
|
||||
if(fSign < 0) {
|
||||
amd::Os::printf(fmtF.data(),"-nan");
|
||||
}
|
||||
else {
|
||||
amd::Os::printf(fmtF.data(),"nan");
|
||||
}
|
||||
}
|
||||
else if (hlModifier) {
|
||||
amd::Os::printf(hlFmt.data(),fArg);
|
||||
}
|
||||
else {
|
||||
amd::Os::printf(fmt.data(),fArg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool hhModifier = (strstr(fmt.c_str(),"hh") != NULL);
|
||||
if (hhModifier) {
|
||||
//current implementation of printf in gcc 4.5.2 runtime libraries, doesn`t recognize "hh" modifier ==>
|
||||
//argument should be explicitly converted to unsigned char (uchar) before printing and
|
||||
//fmt should be updated not to contain "hh" modifier
|
||||
std::string hhFmt = fmt;
|
||||
hhFmt.erase(hhFmt.find_first_of("h"),2);
|
||||
amd::Os::printf(hhFmt.data(), *(reinterpret_cast<const unsigned char*>(argument)));
|
||||
}
|
||||
else if (hlModifier) {
|
||||
amd::Os::printf(hlFmt.data(), *argument);
|
||||
}
|
||||
else {
|
||||
amd::Os::printf(fmt.data(), *argument);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if (printFloat) {
|
||||
if (hlModifier) {
|
||||
amd::Os::printf(hlFmt.data(), *(reinterpret_cast<const double*>(argument)));
|
||||
}
|
||||
else {
|
||||
amd::Os::printf(fmt.data(), *(reinterpret_cast<const double*>(argument)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string out = fmt;
|
||||
// Use 'll' for 64 bit printf
|
||||
out.insert((out.size() - 1), 1, 'l');
|
||||
amd::Os::printf(out.data(), *(reinterpret_cast<const uint64_t*>(argument)));
|
||||
}
|
||||
break;
|
||||
case ConstStr: {
|
||||
const char* str = reinterpret_cast<const char*>(argument);
|
||||
amd::Os::printf(fmt.data(), str);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
amd::Os::printf("Error: Unsupported data size for PrintfDbg. %d bytes",
|
||||
static_cast<int>(size));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
return copiedBytes;
|
||||
}
|
||||
|
||||
void
|
||||
PrintfDbg::outputDbgBuffer(const PrintfInfo& info, const uint32_t* workitemData, size_t& i) const
|
||||
{
|
||||
static const char* specifiers = "cdieEfgGaosuxXp";
|
||||
static const char* modifiers = "hl";
|
||||
static const char* special = "%n";
|
||||
static const std::string sepStr = "%s";
|
||||
const uint32_t* s = workitemData;
|
||||
size_t pos = 0;
|
||||
|
||||
// Find the format string
|
||||
std::string str = info.fmtString_;
|
||||
std::string fmt;
|
||||
size_t posStart, posEnd;
|
||||
|
||||
// Print all arguments
|
||||
// Note: the following code walks through all arguments, provided by the kernel and
|
||||
// finds the corresponding specifier in the format string.
|
||||
// Then it splits the original string into substrings with a single specifier and
|
||||
// uses standard PrintfDbg() to print each argument
|
||||
for (uint j = 0; j < info.arguments_.size(); ++j) {
|
||||
do {
|
||||
posStart = str.find_first_of("%", pos);
|
||||
if (posStart != std::string::npos) {
|
||||
posStart++;
|
||||
// Erase all spaces after %
|
||||
while (str[posStart] == ' ') {
|
||||
str.erase(posStart, 1);
|
||||
}
|
||||
size_t tmp = str.find_first_of(special, posStart);
|
||||
size_t tmp2 = str.find_first_of(specifiers, posStart);
|
||||
// Special cases. Special symbol is located before any specifier
|
||||
if (tmp < tmp2) {
|
||||
posEnd = posStart + 1;
|
||||
fmt = str.substr(pos, posEnd - pos);
|
||||
fmt.erase(posStart - pos - 1, 1);
|
||||
pos = posStart = posEnd;
|
||||
outputArgument(sepStr, false, ConstStr,
|
||||
reinterpret_cast<const uint32_t*>(fmt.data()));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (pos < str.length()) {
|
||||
outputArgument(sepStr, false, ConstStr,reinterpret_cast<const uint32_t*>((str.substr(pos)).data()));
|
||||
}
|
||||
}
|
||||
while (posStart != std::string::npos);
|
||||
|
||||
if (posStart != std::string::npos) {
|
||||
bool printFloat = false;
|
||||
int vectorSize = 0;
|
||||
size_t length;
|
||||
size_t idPos = 0;
|
||||
|
||||
// Search for PrintfDbg specifier in the format string.
|
||||
// It will be a split point for the output
|
||||
posEnd = str.find_first_of(specifiers, posStart);
|
||||
if (posEnd == std::string::npos) {
|
||||
pos = posStart = posEnd;
|
||||
break;
|
||||
}
|
||||
posEnd++;
|
||||
|
||||
size_t curPos = posEnd;
|
||||
vectorSize = checkVectorSpecifier(str, posStart, curPos);
|
||||
|
||||
// Get substring from the last position to the current specifier
|
||||
fmt = str.substr(pos, posEnd - pos);
|
||||
|
||||
// Readjust the string pointer if PrintfDbg outputs a vector
|
||||
if (vectorSize != 0) {
|
||||
size_t posVecSpec = fmt.length()-(curPos + 1);
|
||||
size_t posVecMod = fmt.find_first_of(modifiers,posVecSpec + 1);
|
||||
size_t posMod = str.find_first_of(modifiers,posStart);
|
||||
if(posMod < posEnd){
|
||||
fmt = fmt.erase(posVecSpec, posVecMod - posVecSpec);
|
||||
}
|
||||
else{
|
||||
fmt = fmt.erase(posVecSpec, curPos);
|
||||
}
|
||||
idPos = posStart - pos - 1;
|
||||
}
|
||||
pos = posStart = posEnd;
|
||||
|
||||
// Find out if the argument is a float
|
||||
printFloat = checkFloat(fmt);
|
||||
|
||||
// Is it a scalar value?
|
||||
if (vectorSize == 0) {
|
||||
length = outputArgument(fmt, printFloat, info.arguments_[j], &s[i]);
|
||||
if (0 == length) {
|
||||
return;
|
||||
}
|
||||
i += amd::alignUp(length, sizeof(uint32_t)) / sizeof(uint32_t);
|
||||
}
|
||||
else {
|
||||
size_t elemSize;
|
||||
size_t k = i * sizeof(uint32_t);
|
||||
std::string elementStr = fmt.substr(idPos, fmt.size());
|
||||
|
||||
if (vectorSize == 3) {
|
||||
// 3-component vector's size is defined as 4 * size of each scalar component
|
||||
elemSize = info.arguments_[j] / 4;
|
||||
}
|
||||
else {
|
||||
elemSize = info.arguments_[j] / vectorSize;
|
||||
}
|
||||
|
||||
// Print first element with full string
|
||||
if (0 == outputArgument(fmt, printFloat, elemSize, &s[i])) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print other elemnts with separator if available
|
||||
for (int e = 1; e < vectorSize; ++e) {
|
||||
const char* t = reinterpret_cast<const char*>(s);
|
||||
// Output the vector separator
|
||||
outputArgument(sepStr, false, ConstStr,
|
||||
reinterpret_cast<const uint32_t*>(Separator));
|
||||
|
||||
// Output the next element
|
||||
outputArgument(elementStr, printFloat, elemSize,
|
||||
reinterpret_cast<const uint32_t*>(&t[k + e * elemSize]));
|
||||
}
|
||||
i += (amd::alignUp(info.arguments_[j], sizeof(uint32_t)))
|
||||
/ sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
amd::Os::printf("Error: The arguments don't match the printf format string. printf(%s)",
|
||||
info.fmtString_.data());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos != std::string::npos) {
|
||||
fmt = str.substr(pos, str.size() - pos);
|
||||
outputArgument(sepStr, false, ConstStr,
|
||||
reinterpret_cast<const uint32_t*>(fmt.data()));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbg::clearWorkitems(VirtualGPU& gpu, size_t idxStart, size_t number) const
|
||||
{
|
||||
// Go through all locations for every thread and copy 1
|
||||
for (uint i = idxStart; i < idxStart + number; ++i) {
|
||||
amd::Coord3D dst(i * wiDbgSize(), 0, 0);
|
||||
amd::Coord3D size(sizeof(uint32_t), 0, 0);
|
||||
|
||||
// Copy 1 into the corresponding location in the debug buffer
|
||||
if (!initCntValue_.partialMemCopyTo(
|
||||
gpu, amd::Coord3D(0, 0, 0), dst, size, *dbgBuffer_)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t*
|
||||
PrintfDbg::mapWorkitem(VirtualGPU& gpu, size_t idx, bool* realloc)
|
||||
{
|
||||
uint32_t wiSize = 0;
|
||||
amd::Coord3D src(idx * wiDbgSize(), 0, 0);
|
||||
xferBufRead_ = &(dev().xferRead().acquire());
|
||||
|
||||
// Copy workitem size from the corresponding location in the debug buffer
|
||||
if (!dbgBuffer_->partialMemCopyTo(gpu,
|
||||
src, amd::Coord3D(0, 0, 0), amd::Coord3D(sizeof(uint32_t), 0, 0),
|
||||
*xferBufRead_)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get memory pointer to the satged buffer
|
||||
uint32_t* workitem = reinterpret_cast<uint32_t*>(xferBufRead_->map(&gpu));
|
||||
if (NULL == workitem) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy size value
|
||||
wiSize = *workitem;
|
||||
xferBufRead_->unmap(&gpu);
|
||||
|
||||
// Check if the cuurent workitem almost reached the size limit
|
||||
if ((wiDbgSize() - static_cast<size_t>(wiSize)) < 3) {
|
||||
*realloc = true;
|
||||
}
|
||||
|
||||
// If the current workitem had any output then get the data
|
||||
if ((wiSize > 1) && (wiSize <= wiDbgSize())) {
|
||||
amd::Coord3D size(wiSize * sizeof(uint32_t), 0, 0);
|
||||
|
||||
// Copy the current workitem output data to the staged buffer
|
||||
if (!dbgBuffer_->partialMemCopyTo(
|
||||
gpu, src, amd::Coord3D(0, 0, 0), size, *xferBufRead_) ||
|
||||
// Clear the write pointer back to index 1 for the current workitem
|
||||
!clearWorkitems(gpu, idx, 1)) {
|
||||
LogError("Reading the workitem data failed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get a pointer to the workitem data
|
||||
uint32_t* workitem = reinterpret_cast<uint32_t*>
|
||||
(xferBufRead_->map(&gpu));
|
||||
|
||||
return workitem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
PrintfDbg::unmapWorkitem(VirtualGPU& gpu , const uint32_t* workitemData) const
|
||||
{
|
||||
if (NULL != workitemData) {
|
||||
xferBufRead_->unmap(&gpu);
|
||||
}
|
||||
|
||||
dev().xferRead().release(gpu, *xferBufRead_);
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbgHSA::init(
|
||||
VirtualGPU& gpu,
|
||||
bool printfEnabled)
|
||||
{
|
||||
// Set up debug output buffer (if printf active)
|
||||
if (printfEnabled) {
|
||||
if (!allocate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The first two DWORDs in the printf buffer are as follows:
|
||||
// First DWORD = Offset to where next information is to
|
||||
// be written, initialized to 0
|
||||
// Second DWORD = Number of bytes available for printf data
|
||||
// = buffer size – 2*sizeof(uint32_t)
|
||||
const uint8_t initSize = 2*sizeof(uint32_t);
|
||||
uint8_t sysMem[initSize];
|
||||
memset(sysMem, 0, initSize);
|
||||
uint32_t dbgBufferSize = dbgBuffer_->size() - initSize;
|
||||
memcpy(&sysMem[4], &dbgBufferSize, sizeof(dbgBufferSize));
|
||||
|
||||
// Copy offset and number of bytes available for printf data
|
||||
// into the corresponding location in the debug buffer
|
||||
dbgBuffer_->writeRawData(gpu, initSize, sysMem, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintfDbgHSA::output(
|
||||
VirtualGPU& gpu,
|
||||
bool printfEnabled,
|
||||
const std::vector<PrintfInfo>& printfInfo)
|
||||
{
|
||||
if (printfEnabled) {
|
||||
uint32_t offsetSize = 0;
|
||||
xferBufRead_ = &(dev().xferRead().acquire());
|
||||
|
||||
// Copy offset from the first DWORD in the debug buffer
|
||||
if (!dbgBuffer_->partialMemCopyTo(gpu,
|
||||
amd::Coord3D(0, 0, 0), amd::Coord3D(0, 0, 0),
|
||||
amd::Coord3D(sizeof(uint32_t), 0, 0),*xferBufRead_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get memory pointer to the satged buffer
|
||||
uint32_t* dbgBufferPtr = reinterpret_cast<uint32_t*>(xferBufRead_->map(&gpu));
|
||||
if (NULL == dbgBufferPtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
offsetSize = *dbgBufferPtr;
|
||||
xferBufRead_->unmap(&gpu);
|
||||
|
||||
if (offsetSize == 0) {
|
||||
LogError("\n The printf buffer is empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy the buffer data (i.e., the printfID followed by the
|
||||
//argument data for each printf call in th kernel) to the staged buffer
|
||||
if (!dbgBuffer_->partialMemCopyTo(gpu,
|
||||
amd::Coord3D(2*sizeof(uint32_t), 0, 0), amd::Coord3D(0, 0, 0),
|
||||
offsetSize,*xferBufRead_)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a pointer to the buffer data
|
||||
dbgBufferPtr = reinterpret_cast<uint32_t*>(xferBufRead_->map(&gpu));
|
||||
if (NULL == dbgBufferPtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint>::const_iterator ita;
|
||||
uint sb = 0;
|
||||
uint sbt = 0;
|
||||
size_t idx = 1;
|
||||
|
||||
// parse the debug buffer
|
||||
while (sbt < offsetSize) {
|
||||
assert(((*dbgBufferPtr) < printfInfo.size()) &&
|
||||
"Cound't find the reported PrintfID!");
|
||||
const PrintfInfo& info = printfInfo[(*dbgBufferPtr)];
|
||||
sb += sizeof(uint32_t);
|
||||
for (ita = info.arguments_.begin();
|
||||
ita != info.arguments_.end(); ++ita){
|
||||
sb += *ita;
|
||||
}
|
||||
|
||||
// There's something in the debug buffer
|
||||
outputDbgBuffer(info, dbgBufferPtr, idx);
|
||||
|
||||
sbt += sb;
|
||||
dbgBufferPtr += sb/sizeof(uint32_t);
|
||||
sb = 0;
|
||||
}
|
||||
|
||||
xferBufRead_->unmap(&gpu);
|
||||
dev().xferRead().release(gpu, *xferBufRead_);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUPRINTFDBG_HPP_
|
||||
#define GPUPRINTFDBG_HPP_
|
||||
|
||||
/*! \addtogroup GPU GPU Device Implementation
|
||||
* @{
|
||||
*/
|
||||
#ifndef isinf
|
||||
#ifdef _MSC_VER
|
||||
#define isinf(X) (!_finite(X) && !_isnan(X))
|
||||
#endif //_MSC_VER
|
||||
#endif //isinf
|
||||
|
||||
#ifndef isnan
|
||||
#ifdef _MSC_VER
|
||||
#define isnan(X) (_isnan(X))
|
||||
#endif //_MSC_VER
|
||||
#endif //isnan
|
||||
|
||||
#ifndef copysign
|
||||
#ifdef _MSC_VER
|
||||
#define copysign(X,Y) (_copysign(X,Y))
|
||||
#endif //_MSC_VER
|
||||
#endif //copysign
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
//! Printf info structure
|
||||
struct PrintfInfo
|
||||
{
|
||||
std::string fmtString_; //!< formated string for printf
|
||||
std::vector<uint> arguments_; //!< passed arguments to the printf() call
|
||||
};
|
||||
|
||||
class Kernel;
|
||||
class VirtualGPU;
|
||||
class Memory;
|
||||
|
||||
class PrintfDbg : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Debug buffer size per workitem
|
||||
static const uint WorkitemDebugSize = 4096;
|
||||
|
||||
//! Default constructor
|
||||
PrintfDbg(
|
||||
Device& device,
|
||||
FILE* file = NULL
|
||||
);
|
||||
|
||||
//! Destructor
|
||||
~PrintfDbg();
|
||||
|
||||
//! Creates the PrintfDbg object
|
||||
bool create();
|
||||
|
||||
//! Initializes the debug buffer before kernel's execution
|
||||
bool init(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
bool printfEnabled, //!< checks for printf
|
||||
const amd::NDRange& size //!< Kernel's workload
|
||||
);
|
||||
|
||||
//! Prints the kernel's debug informaiton from the buffer
|
||||
bool output(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
bool printfEnabled, //!< checks for printf
|
||||
const amd::NDRange& size, //!< Kernel's workload
|
||||
const std::vector<PrintfInfo>& printfInfo //!< printf info
|
||||
);
|
||||
|
||||
//! Returns the debug buffer offset
|
||||
uint64_t bufOffset() const;
|
||||
|
||||
//! Debug buffer size per workitem
|
||||
size_t wiDbgSize() const { return wiDbgSize_; }
|
||||
|
||||
//! Returns debug buffer object
|
||||
Memory* dbgBuffer() const { return dbgBuffer_; }
|
||||
|
||||
protected:
|
||||
Memory* dbgBuffer_; //!< Buffer to hold debug output
|
||||
FILE* dbgFile_; //!< Debug file
|
||||
Device& gpuDevice_; //!< GPU device object
|
||||
Resource* xferBufRead_; //!< Transfer buffer for the dump read
|
||||
|
||||
//! Gets GPU device object
|
||||
Device& dev() const { return gpuDevice_; }
|
||||
|
||||
//! Allocates the debug buffer
|
||||
bool allocate(
|
||||
bool realloc = false //!< If TRUE then reallocate the debug memory
|
||||
);
|
||||
|
||||
//! Returns TRUE if a float value has to be printed
|
||||
bool checkFloat(
|
||||
const std::string& fmt //!< Format string
|
||||
) const;
|
||||
|
||||
//! Returns TRUE if a string value has to be printed
|
||||
bool checkString(
|
||||
const std::string& fmt //!< Format string
|
||||
) const;
|
||||
|
||||
//! Finds the specifier in the format string
|
||||
int checkVectorSpecifier(
|
||||
const std::string& fmt, //!< Format string
|
||||
size_t startPos, //!< Start position for processing
|
||||
size_t& curPos //!< End position for processing
|
||||
) const;
|
||||
|
||||
//! Outputs an argument
|
||||
size_t outputArgument(
|
||||
const std::string& fmt, //!< Format strint
|
||||
bool printFloat, //!< Argument is a float value
|
||||
size_t size, //!< Argument's size
|
||||
const uint32_t* argument //!< Argument's location
|
||||
) const;
|
||||
|
||||
//! Displays the PrintfDbg
|
||||
void outputDbgBuffer(
|
||||
const PrintfInfo& info, //!< printf info
|
||||
const uint32_t* workitemData, //!< The PrintfDbg dump buffer
|
||||
size_t& i //!< index to the data in the buffer
|
||||
) const;
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
PrintfDbg(const PrintfDbg&);
|
||||
|
||||
//! Disable assignment
|
||||
PrintfDbg& operator=(const PrintfDbg&);
|
||||
|
||||
//! Returns the pointer to the workitem data block
|
||||
bool clearWorkitems(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
size_t idxStart, //!< Workitem global index start
|
||||
size_t number //!< Number of workitems to clear
|
||||
) const;
|
||||
|
||||
//! Returns the pointer to the workitem data block
|
||||
uint32_t* mapWorkitem(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
size_t idx, //!< Workitem global index
|
||||
bool* realloc //!< Returns TRUE if workitem reached the buffer limit
|
||||
);
|
||||
|
||||
//! Unamp the staged buffer
|
||||
void unmapWorkitem(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
const uint32_t* workitemData //!< The PrintfDbg dump buffer
|
||||
) const;
|
||||
|
||||
size_t wiDbgSize_; //!< Workitem debug size
|
||||
Resource initCntValue_; //!< Initialized count value
|
||||
};
|
||||
class PrintfDbgHSA : public PrintfDbg
|
||||
{
|
||||
public:
|
||||
|
||||
//! Default constructor
|
||||
PrintfDbgHSA(
|
||||
Device& device,
|
||||
FILE* file = NULL
|
||||
): PrintfDbg(device, file) { }
|
||||
|
||||
//! Initializes the debug buffer before kernel's execution
|
||||
bool init(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
bool printfEnabled //!< checks for printf
|
||||
);
|
||||
|
||||
//! Prints the kernel's debug informaiton from the buffer
|
||||
bool output(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
bool printfEnabled, //!< checks for printf
|
||||
const std::vector<PrintfInfo>& printfInfo //!< printf info
|
||||
);
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
PrintfDbgHSA(const PrintfDbgHSA&);
|
||||
|
||||
//! Disable assignment
|
||||
PrintfDbgHSA& operator=(const PrintfDbgHSA&);
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUPRINTFDBG_HPP_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,494 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUPROGRAM_HPP_
|
||||
#define GPUPROGRAM_HPP_
|
||||
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
#include "device/gpu/gpubinary.hpp"
|
||||
|
||||
namespace amd {
|
||||
namespace option {
|
||||
class Options;
|
||||
} // option
|
||||
} // amd
|
||||
|
||||
//! \namespace gpu GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
/*! \addtogroup GPU GPU Device Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! \struct ILFunc for the opencl program processing
|
||||
struct ILFunc : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! \struct CodeRange for the code ranges
|
||||
struct SourceRange : public amd::EmbeddedObject
|
||||
{
|
||||
size_t begin_; //!< start code position
|
||||
size_t end_; //!< end code position
|
||||
};
|
||||
|
||||
//! \enum IL function state
|
||||
enum State
|
||||
{
|
||||
Unknown = 0x00000000, //! unknown function
|
||||
Regular = 0x00000001, //! regular function from the program
|
||||
Kernel = 0x00000002 //! kernel function from the program
|
||||
};
|
||||
|
||||
//! Default constructor
|
||||
ILFunc()
|
||||
: name_("")
|
||||
, index_(0)
|
||||
, state_(Unknown)
|
||||
, privateSize_(0)
|
||||
, localSize_(0)
|
||||
, hwPrivateSize_(0)
|
||||
, hwLocalSize_(0)
|
||||
, flags_(0)
|
||||
{
|
||||
code_.begin_ = code_.end_ = 0;
|
||||
metadata_.begin_ = metadata_.end_ = 0;
|
||||
}
|
||||
|
||||
//! Copy constructor
|
||||
ILFunc(const ILFunc& func) { *this = func; }
|
||||
|
||||
//! Destructor
|
||||
~ILFunc() {}
|
||||
|
||||
//! Overloads operator=
|
||||
ILFunc& operator=(const ILFunc& func)
|
||||
{
|
||||
name_ = func.name_;
|
||||
index_ = func.index_;
|
||||
code_ = func.code_;
|
||||
metadata_ = func.metadata_;
|
||||
state_ = func.state_;
|
||||
privateSize_ = func.privateSize_;
|
||||
localSize_ = func.localSize_;
|
||||
hwPrivateSize_ = func.hwPrivateSize_;
|
||||
hwLocalSize_ = func.hwLocalSize_;
|
||||
flags_ = func.flags_;
|
||||
|
||||
// Note: we don't copy calls_ and macros_
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string name_; //!< kernel's name
|
||||
uint index_; //!< kernel's index
|
||||
SourceRange code_; //!< the entire function range in the source
|
||||
SourceRange metadata_; //!< the metadata range
|
||||
State state_; //!< the function is real, and not intrinsic
|
||||
uint privateSize_; //!< private ring allocation by the function
|
||||
uint localSize_; //!< local ring allocation by the function
|
||||
uint hwPrivateSize_; //!< HW private ring allocation by the function
|
||||
uint hwLocalSize_; //!< HW local ring allocation by the function
|
||||
uint flags_; //!< The IL func flags/properties
|
||||
|
||||
std::vector<const ILFunc*> calls_; //! Functions called from the current
|
||||
std::vector<uint> macros_; //! Macros, used in the IL function
|
||||
};
|
||||
|
||||
//! \class empty program
|
||||
class NullProgram : public device::Program
|
||||
{
|
||||
friend class ClBinary;
|
||||
public:
|
||||
//! Default constructor
|
||||
NullProgram(NullDevice& nullDev) : device::Program(nullDev) , patch_(0) {}
|
||||
|
||||
//! Default destructor
|
||||
~NullProgram();
|
||||
|
||||
// Initialize Binary for GPU
|
||||
virtual bool initClBinary();
|
||||
// Release Binary for GPU
|
||||
virtual void releaseClBinary();
|
||||
|
||||
//! Returns global constant buffers
|
||||
const std::vector<uint>& glbCb() const { return glbCb_; }
|
||||
|
||||
protected:
|
||||
//! pre-compile setup for GPU
|
||||
virtual bool initBuild(amd::option::Options* options);
|
||||
|
||||
//! post-compile setup for GPU
|
||||
virtual bool finiBuild(bool isBuildGood);
|
||||
|
||||
/*! \brief Compiles GPU CL program to LLVM binary (compiler frontend)
|
||||
*
|
||||
* \return True if we successefully compiled a GPU program
|
||||
*/
|
||||
virtual bool compileImpl(
|
||||
const std::string& sourceCode, //!< the program's source code
|
||||
const std::vector<const std::string*>& headers, //!< header souce codes
|
||||
const char** headerIncludeNames,//!< include names of headers
|
||||
amd::option::Options* options //!< compile options's object
|
||||
);
|
||||
|
||||
/*! \brief Compiles LLVM binary to IL code (compiler backend: link+opt+codegen)
|
||||
*
|
||||
* \return The build error code
|
||||
*/
|
||||
int compileBinaryToIL(
|
||||
amd::option::Options* options //!< options for compilation
|
||||
);
|
||||
|
||||
/*! \brief Links the compiled IL program with HW
|
||||
*
|
||||
* \return True if we successefully linked a GPU program
|
||||
*/
|
||||
virtual bool linkImpl(
|
||||
amd::option::Options* options = NULL //!< options object
|
||||
);
|
||||
virtual bool linkImpl(
|
||||
const std::vector<device::Program*>& inputPrograms,
|
||||
amd::option::Options* options = NULL, //!< options object
|
||||
bool createLibrary = false
|
||||
);
|
||||
|
||||
virtual bool createBinary(amd::option::Options* options);
|
||||
|
||||
|
||||
/*! \brief Parses the GPU program and finds all available kernels
|
||||
*
|
||||
* \return True if we successefully parsed the GPU program
|
||||
*/
|
||||
bool parseKernels(
|
||||
const std::string& source //! the program's source code
|
||||
);
|
||||
|
||||
/*! \brief Parse all functions in the program
|
||||
*
|
||||
* \return True if we successefully parsed all functions
|
||||
*/
|
||||
bool parseAllILFuncs(
|
||||
const std::string& source //! the program's source code
|
||||
);
|
||||
|
||||
/*! \brief Parse a function's metadata given as source[posBegin:posEnd-1]
|
||||
*
|
||||
* \return True if we successefully parsed the given metadata
|
||||
*/
|
||||
bool parseFuncMetadata(
|
||||
const std::string& source, //! string that contains metadata
|
||||
size_t posBegin, //! begin of metadata in 'source'
|
||||
size_t posEnd //! end of metadata in 'source'
|
||||
);
|
||||
|
||||
/*! \brief Finds functions with the given start and end string in the
|
||||
* program
|
||||
*
|
||||
* \return True if we successefully found all functions
|
||||
*/
|
||||
bool findILFuncs(
|
||||
const std::string& source, //! the program's source code
|
||||
const std::string& func_start, //! the start string of a function
|
||||
const std::string& func_end, //! the end string of a function
|
||||
size_t& lastFuncPos //! pos to the end of the last func in 'source'
|
||||
);
|
||||
|
||||
|
||||
/*! \brief Finds all functions in the program
|
||||
*
|
||||
* \return True if we successefully found all functions
|
||||
*/
|
||||
bool findAllILFuncs(
|
||||
const std::string& source, //! the program's source code
|
||||
size_t& lastFuncPos //! pos to the end of the last func in 'source'
|
||||
);
|
||||
|
||||
/*! \brief Finds function, corresponded to the provided unique index
|
||||
*
|
||||
* \return Pointer to the ILFunc structure
|
||||
*/
|
||||
ILFunc* findILFunc(
|
||||
uint index //! the function unique index
|
||||
);
|
||||
|
||||
//! Destroys all objects, associated with the IL functions
|
||||
void freeAllILFuncs();
|
||||
|
||||
/*! \brief Finds if a provided function is called from the base function
|
||||
*
|
||||
* \return True if a function is used from the base one
|
||||
*/
|
||||
bool isCalled(
|
||||
const ILFunc* base, //!< The base function
|
||||
const ILFunc* func //!< Function to check for usage
|
||||
);
|
||||
|
||||
//! Patches the "main" function with the call to the current kernel
|
||||
void patchMain(
|
||||
std::string& kernel, //! The current kernel's code for compilation
|
||||
uint index //! Index of the current kernel in the program
|
||||
);
|
||||
|
||||
//! Adds the IL function object into the list of functions
|
||||
void addFunc(ILFunc* func) { funcs_.push_back(func); }
|
||||
|
||||
//! Empty implementation, since we don't have real HW
|
||||
virtual bool allocGlobalData(
|
||||
const void* globalData, //!< Pointer to the global data
|
||||
size_t dataSize, //!< The global data size
|
||||
uint index //!< Index for the global data store (0 - global heap)
|
||||
) { glbCb_.push_back(index); return true; }
|
||||
|
||||
//! Load binary for offline device.
|
||||
virtual bool loadBinary(bool *hasRecompiled);
|
||||
|
||||
//! Create NullKernel for compiling to isa.
|
||||
virtual NullKernel* createKernel(
|
||||
const std::string& name, //!< The kernel's name
|
||||
const Kernel::InitData* initData, //!< Initialization data
|
||||
const std::string& code, //!< IL source code
|
||||
const std::string& metadata, //!< the kernel metadata structure
|
||||
bool* created, //!< True if the object was created
|
||||
const void* binaryCode = NULL, //!< binary machine code for CAL
|
||||
size_t binarySize = 0 //!< the machine code size
|
||||
);
|
||||
|
||||
ClBinary* clBinary() {
|
||||
return static_cast<ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
const ClBinary* clBinary() const {
|
||||
return static_cast<const ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
|
||||
/*! Get all per-kernel IL from programIL, where programIL is the IL for the
|
||||
* whole compilation unit.
|
||||
*/
|
||||
bool getAllKernelILs(std::map<std::string, std::string>& allKernelILs,
|
||||
std::string& programIL, const char* ilKernelName);
|
||||
|
||||
protected:
|
||||
std::vector<PrintfInfo> printf_; //!< Format strings for GPU printf support
|
||||
std::vector<uint> glbCb_; //!< Global constant buffers
|
||||
|
||||
virtual bool isElf(const char* bin) const {
|
||||
return amd::isElfMagic(bin);
|
||||
}
|
||||
|
||||
virtual const aclTargetInfo & info(const char * str = "");
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
NullProgram(const NullProgram&);
|
||||
|
||||
//! Disable operator=
|
||||
NullProgram& operator=(const NullProgram&);
|
||||
|
||||
//! Initializes the global data store
|
||||
bool initGlobalData(
|
||||
const std::string& source, //!< the program's source code
|
||||
size_t start //!< start position for the global data search
|
||||
);
|
||||
|
||||
//! Return a typecasted GPU device
|
||||
gpu::NullDevice& dev()
|
||||
{ return const_cast<gpu::NullDevice&>(
|
||||
static_cast<const gpu::NullDevice&>(device())); }
|
||||
|
||||
size_t patch_; //!< Patch call position in the source code.
|
||||
std::vector<ILFunc*> funcs_; //!< list of all functions.
|
||||
|
||||
std::string ilProgram_; //!< IL program after compilation
|
||||
};
|
||||
|
||||
//! \class GPU program
|
||||
class Program : public NullProgram
|
||||
{
|
||||
public:
|
||||
//! GPU program constructor
|
||||
Program(Device& gpuDev)
|
||||
: NullProgram(gpuDev)
|
||||
, glbData_(NULL)
|
||||
{}
|
||||
|
||||
//! GPU program destructor
|
||||
~Program();
|
||||
|
||||
//! Get the global data store for this program
|
||||
gpu::Memory* glbData() const { return glbData_; }
|
||||
|
||||
//! Returns TRUE if we successfully allocated the global data store
|
||||
//! in video memory
|
||||
bool allocGlobalData(
|
||||
const void* globalData, //!< Pointer to the global data
|
||||
size_t dataSize, //!< The global data size
|
||||
uint index //!< Index for the global data store (0 - global heap)
|
||||
);
|
||||
|
||||
//! Returns TRUE if we could
|
||||
virtual bool loadBinary(bool* hasRecompiled);
|
||||
|
||||
//! Creates the GPU kernel (return base type)
|
||||
virtual NullKernel* createKernel(
|
||||
const std::string& name, //!< The kernel's name
|
||||
const Kernel::InitData* initData, //!< Initialization data
|
||||
const std::string& code, //!< IL source code
|
||||
const std::string& metadata, //!< the kernel metadata structure
|
||||
bool* created, //!< True if the object was created
|
||||
const void* binaryCode = NULL, //!< binary machine code for CAL
|
||||
size_t binarySize = 0 //!< the machine code size
|
||||
);
|
||||
|
||||
typedef std::map<uint, gpu::Memory*> HwConstBuffers;
|
||||
|
||||
//! Global HW constant buffers
|
||||
const HwConstBuffers& glbHwCb() const { return constBufs_; }
|
||||
|
||||
//! Returns pritnf info array
|
||||
const std::vector<PrintfInfo>& printfInfo() const { return printf_; }
|
||||
|
||||
//! Return a typecasted GPU device
|
||||
gpu::Device& dev()
|
||||
{ return const_cast<gpu::Device&>(
|
||||
static_cast<const gpu::Device&>(device())); }
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Program(const Program&);
|
||||
|
||||
//! Disable operator=
|
||||
Program& operator=(const Program&);
|
||||
|
||||
HwConstBuffers constBufs_; //!< Constant buffers for the global store
|
||||
gpu::Memory* glbData_; //!< Global data store
|
||||
};
|
||||
|
||||
|
||||
//! \class HSAIL program
|
||||
class HSAILProgram : public device::Program
|
||||
{
|
||||
friend class ClBinary;
|
||||
public:
|
||||
//! Default constructor
|
||||
HSAILProgram(Device& device);
|
||||
//! Default destructor
|
||||
~HSAILProgram();
|
||||
|
||||
//! Returns the aclBinary associated with the progrm
|
||||
aclBinary* binaryElf() const {
|
||||
return static_cast<aclBinary*>(binaryElf_); }
|
||||
|
||||
void setGlobalStore(Memory* mem) { globalStore_ = mem; }
|
||||
|
||||
const Memory* globalStore() const { return globalStore_; }
|
||||
|
||||
//! Return a typecasted GPU device
|
||||
gpu::Device& dev()
|
||||
{ return const_cast<gpu::Device&>(
|
||||
static_cast<const gpu::Device&>(device())); }
|
||||
|
||||
//! Returns GPU kernel table
|
||||
const Memory* kernelTable() const { return kernels_; }
|
||||
|
||||
//! Adds all kernels to the mem handle lists
|
||||
void fillResListWithKernels(std::vector<const Resource*>& memList) const;
|
||||
|
||||
//! Returns the maximum number of scratch regs used in the program
|
||||
uint maxScratchRegs() const { return maxScratchRegs_; }
|
||||
|
||||
//! Add internal static sampler
|
||||
void addSampler(Sampler* sampler) { staticSamplers_.push_back(sampler); }
|
||||
|
||||
protected:
|
||||
//! pre-compile setup for GPU
|
||||
virtual bool initBuild(amd::option::Options* options);
|
||||
|
||||
//! post-compile setup for GPU
|
||||
virtual bool finiBuild(bool isBuildGood);
|
||||
|
||||
/*! \brief Compiles GPU CL program to LLVM binary (compiler frontend)
|
||||
*
|
||||
* \return True if we successefully compiled a GPU program
|
||||
*/
|
||||
virtual bool compileImpl(
|
||||
const std::string& sourceCode, //!< the program's source code
|
||||
const std::vector<const std::string*>& headers,
|
||||
const char** headerIncludeNames,
|
||||
amd::option::Options* options //!< compile options's object
|
||||
);
|
||||
|
||||
aclType getNextCompilationStageFromBinary();
|
||||
|
||||
/*! \brief Compiles LLVM binary to FSAIL code (compiler backend: link+opt+codegen)
|
||||
*
|
||||
* \return The build error code
|
||||
*/
|
||||
int compileBinaryToFSAIL(
|
||||
amd::option::Options* options //!< options for compilation
|
||||
);
|
||||
|
||||
virtual bool linkImpl(amd::option::Options* options);
|
||||
|
||||
//! Link the device programs.
|
||||
virtual bool linkImpl (const std::vector<device::Program*>& inputPrograms,
|
||||
amd::option::Options* options,
|
||||
bool createLibrary);
|
||||
|
||||
virtual bool createBinary(amd::option::Options* options);
|
||||
|
||||
//! Initialize Binary
|
||||
virtual bool initClBinary();
|
||||
|
||||
//! Release the Binary
|
||||
virtual void releaseClBinary();
|
||||
|
||||
virtual const aclTargetInfo & info(const char * str = "") {
|
||||
return info_;
|
||||
}
|
||||
|
||||
virtual bool isElf(const char* bin) const {
|
||||
return amd::isElfMagic(bin);
|
||||
//return false;
|
||||
}
|
||||
|
||||
//! Returns the binary
|
||||
// This should ensure that the binary is updated with all the kernels
|
||||
// ClBinary& clBinary() { return binary_; }
|
||||
ClBinary* clBinary() {
|
||||
return static_cast<ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
const ClBinary* clBinary() const {
|
||||
return static_cast<const ClBinary*>(device::Program::clBinary());
|
||||
}
|
||||
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
HSAILProgram(const HSAILProgram&);
|
||||
|
||||
//! Disable operator=
|
||||
HSAILProgram& operator=(const HSAILProgram&);
|
||||
|
||||
//! Returns all the options to be appended while passing to the
|
||||
//compiler library
|
||||
std::string hsailOptions();
|
||||
|
||||
//! Allocate kernel table
|
||||
bool allocKernelTable();
|
||||
|
||||
std::string openCLSource_; //!< Original OpenCL source
|
||||
std::string HSAILProgram_; //!< FSAIL program after compilation
|
||||
std::string llvmBinary_; //!< LLVM IR binary code
|
||||
aclBinary* binaryElf_; //!< Binary for the new compiler library
|
||||
void* rawBinary_; //!< Pointer to the raw binary
|
||||
aclBinaryOptions binOpts_; //!< Binary options to create aclBinary
|
||||
Memory* globalStore_; //!< Global memory for the program
|
||||
Memory* kernels_; //!< Table with kernel object pointers
|
||||
uint maxScratchRegs_; //!< Maximum number of scratch regs used in the program by individual kernel
|
||||
std::list<Sampler*> staticSamplers_; //!< List od internal static samplers
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUPROGRAM_HPP_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,508 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPURESOURCE_HPP_
|
||||
#define GPURESOURCE_HPP_
|
||||
|
||||
#include "platform/command.hpp"
|
||||
#include "platform/program.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
|
||||
//! \namespace gpu GPU Resource Implementation
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class VirtualGPU;
|
||||
|
||||
/*! \addtogroup GPU GPU Resource Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
class GslResourceReference : public amd::ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
GslResourceReference(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
gslMemObject gslResource, //!< CAL resource
|
||||
gslMemObject gslResOriginal = NULL //!< Original CAL resource
|
||||
);
|
||||
|
||||
//! Get CAL resource
|
||||
gslMemObject gslResource() const { return resource_; }
|
||||
|
||||
//! Original CAL resource
|
||||
gslMemObject gslOriginal() const { return (resOriginal_ == 0) ? resource_ : resOriginal_; }
|
||||
|
||||
const Device& device_; //!< GPU device
|
||||
gslMemObject resource_; //!< GSL resource object
|
||||
gslMemObject resOriginal_; //!< Original resource object, NULL if no channel order
|
||||
void* cpuAddress_; //!< CPU address of this memory
|
||||
|
||||
protected:
|
||||
//! Default destructor
|
||||
~GslResourceReference();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
GslResourceReference(const GslResourceReference&);
|
||||
|
||||
//! Disable operator=
|
||||
GslResourceReference& operator=(const GslResourceReference&);
|
||||
};
|
||||
|
||||
//! GPU resource
|
||||
class Resource : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
enum InteropType {
|
||||
InteropTypeless = 0,
|
||||
InteropVertexBuffer,
|
||||
InteropIndexBuffer,
|
||||
InteropRenderBuffer,
|
||||
InteropTexture,
|
||||
InteropTextureViewLevel,
|
||||
InteropTextureViewCube,
|
||||
InteropSurface
|
||||
};
|
||||
|
||||
struct CreateParams : public amd::StackObject {
|
||||
amd::Memory* owner_; //!< Resource's owner
|
||||
VirtualGPU* gpu_; //!< Resource won't be shared between multiple queues
|
||||
CreateParams(): owner_(NULL), gpu_(NULL) {}
|
||||
};
|
||||
|
||||
struct PinnedParams : public CreateParams {
|
||||
const amd::HostMemoryReference* hostMemRef_;//!< System memory pointer for pinning
|
||||
size_t size_; //!< System memory size
|
||||
};
|
||||
|
||||
struct ViewParams : public CreateParams {
|
||||
size_t offset_; //!< Alias resource offset
|
||||
size_t size_; //!< Alias resource size
|
||||
const Resource* resource_; //!< Parent resource for the view creation
|
||||
const void* memory_;
|
||||
};
|
||||
|
||||
struct ImageViewParams : public CreateParams {
|
||||
size_t level_; //!< Image mip level for a new view
|
||||
size_t layer_; //!< Image layer for a new view
|
||||
const Resource* resource_; //!< Parent resource for the view creation
|
||||
const void* memory_;
|
||||
};
|
||||
|
||||
struct ImageBufferParams : public CreateParams {
|
||||
const Resource* resource_; //!< Parent resource for the image creation
|
||||
const void* memory_;
|
||||
};
|
||||
|
||||
struct OGLInteropParams : public CreateParams {
|
||||
InteropType type_; //!< OGL resource type
|
||||
CALuint handle_; //!< OGL resource handle
|
||||
uint mipLevel_; //!< Texture mip level
|
||||
uint layer_; //!< Texture layer
|
||||
void* glPlatformContext_;
|
||||
void* glDeviceContext_;
|
||||
uint flags_;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
struct D3DInteropParams : public CreateParams {
|
||||
InteropType type_; //!< D3D resource type
|
||||
void* iDirect3D_; //!< D3D resource interface object
|
||||
HANDLE handle_; //!< D3D resource handle
|
||||
uint mipLevel_; //!< Texture mip level
|
||||
int layer_; //!< Texture layer
|
||||
uint misc; //!< miscellaneous cases
|
||||
};
|
||||
#endif // _WIN32
|
||||
|
||||
//! Resource memory
|
||||
enum MemoryType
|
||||
{
|
||||
Empty = 0x0, //!< resource is empty
|
||||
Local, //!< resource in local memory
|
||||
Persistent, //!< resource in persistent memory
|
||||
Remote, //!< resource in nonlocal memory
|
||||
RemoteUSWC, //!< resource in nonlocal memory
|
||||
Pinned, //!< resource in pinned system memory
|
||||
View, //!< resource is an alias
|
||||
OGLInterop, //!< resource is an OGL memory object
|
||||
D3D10Interop, //!< resource is a D3D10 memory object
|
||||
D3D11Interop, //!< resource is a D3D11 memory object
|
||||
Heap, //!< resource is a heap
|
||||
ImageView, //!< resource is a view to some image
|
||||
ImageBuffer, //!< resource is an image view of a buffer
|
||||
BusAddressable, //!< resource is a bus addressable memory
|
||||
ExternalPhysical, //!< resource is an external physical memory
|
||||
D3D9Interop, //!< resource is a D3D9 memory object
|
||||
Scratch //!< resource is scratch memory
|
||||
};
|
||||
|
||||
//! Resource map flags
|
||||
enum MapFlags
|
||||
{
|
||||
Discard = 0x00000001, //!< discard lock
|
||||
NoOverwrite = 0x00000002, //!< lock with no overwrite
|
||||
ReadOnly = 0x00000004, //!< lock for read only operation
|
||||
WriteOnly = 0x00000008, //!< lock for write only operation
|
||||
NoWait = 0x00000010, //!< lock with no wait
|
||||
};
|
||||
|
||||
//! CAL resource descriptor
|
||||
struct CalResourceDesc : public amd::HeapObject
|
||||
{
|
||||
MemoryType type_; //!< Memory type
|
||||
size_t width_; //!< CAL resource width
|
||||
size_t height_; //!< CAL resource height
|
||||
size_t depth_; //!< CAL resource depth
|
||||
cmSurfFmt format_; //!< GSL resource format
|
||||
CALuint flags_; //!< CAL resource flags, used in creation
|
||||
size_t pitch_; //!< CAL resource pitch, valid if locked
|
||||
CALuint slice_; //!< CAL resource slice, valid if locked
|
||||
gslChannelOrder channelOrder_; //!< GSL resource channel order
|
||||
gslMemObjectAttribType dimension_; //!< GSL resource dimension
|
||||
cl_mem_object_type imageType_; //!< CL image type
|
||||
union {
|
||||
struct {
|
||||
uint dimSize_ : 2; //!< Dimension size
|
||||
uint cardMemory_ : 1; //!< GSL resource is in video memory
|
||||
uint imageArray_ : 1; //!< GSL resource is an array of images
|
||||
uint buffer_ : 1; //!< GSL resource is a buffer
|
||||
uint tiled_ : 1; //!< GSL resource is tiled
|
||||
uint SVMRes_ : 1; //!< SVM flag to the cal resource
|
||||
};
|
||||
uint state_;
|
||||
};
|
||||
};
|
||||
|
||||
//! Constructor of 1D Resource object
|
||||
Resource(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
size_t width, //!< resource width
|
||||
cmSurfFmt format //!< resource format
|
||||
);
|
||||
|
||||
//! Constructor of Image Resource object
|
||||
Resource(
|
||||
const Device& gpuDev, //!< GPU device object
|
||||
size_t width, //!< resource width
|
||||
size_t height, //!< resource height
|
||||
size_t depth, //!< resource depth
|
||||
cmSurfFmt format, //!< resource format
|
||||
gslChannelOrder chOrder, //!< resource channel order
|
||||
cl_mem_object_type imageType //!< CL image type
|
||||
);
|
||||
|
||||
//! Destructor of the resource
|
||||
virtual ~Resource();
|
||||
|
||||
/*! \brief Creates a CAL object, associated with the resource
|
||||
*
|
||||
* \return True if we succesfully created a CAL resource
|
||||
*/
|
||||
virtual bool create(
|
||||
MemoryType memType, //!< memory type
|
||||
CreateParams* params = 0, //!< special parameters for resource allocation
|
||||
bool heap = false //!< Global heap allocation for not VM mode
|
||||
);
|
||||
|
||||
/*! \brief Reallocates a CAL object, associated with the resource
|
||||
*
|
||||
* \return True if we succesfully reallocated a CAL resource
|
||||
*/
|
||||
bool reallocate(
|
||||
CreateParams* params = 0 //!< special parameters for resource allocation
|
||||
);
|
||||
|
||||
/*! \brief Copies a subregion of memory from one resource to another
|
||||
*
|
||||
* This is a general copy from anything to anything (as long as it fits).
|
||||
* All positions and sizes are given in bytes. Note, however, that only
|
||||
* a subset of this general interface is currently implemented.
|
||||
*
|
||||
* \return true if successful
|
||||
*/
|
||||
bool partialMemCopyTo(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
const amd::Coord3D& srcOrigin, //!< Origin of the source region
|
||||
const amd::Coord3D& dstOrigin, //!< Origin of the destination region
|
||||
const amd::Coord3D& size, //!< Size of the region to copy
|
||||
Resource& dstResource, //!< Destination resource
|
||||
bool enableRectCopy = false, //!< Rectangular DMA support
|
||||
bool flushDMA = false //!< Flush DMA if requested
|
||||
) const;
|
||||
|
||||
/*! \brief Copies size/4 DWORD of memory to a surface
|
||||
*
|
||||
* This is a raw copy to any surface using a CP packet.
|
||||
* Size needs to be atleast a DWORD or multiple
|
||||
*
|
||||
*/
|
||||
void writeRawData(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
size_t size, //!< Size in bytes of data to be copied(multiple of DWORDS)
|
||||
const void* data, //!< Data to be copied
|
||||
bool waitForEvent //!< Wait for event complete
|
||||
) const;
|
||||
|
||||
//! Returns the offset in GPU memory for aliases
|
||||
size_t offset() const { return offset_; }
|
||||
|
||||
//! Returns the offset in GPU heap
|
||||
uint64_t hbOffset() const { return hbOffset_; }
|
||||
|
||||
//! Returns the pinned memory offset
|
||||
uint64_t pinOffset() const { return pinOffset_; }
|
||||
|
||||
//! Returns the size in GPU heap
|
||||
uint64_t hbSize() const { return hbSize_; }
|
||||
|
||||
//! Returns the GPU device that owns this resource
|
||||
const Device& dev() const { return gpuDevice_; }
|
||||
|
||||
//! Returns the CAL descriptor for resource
|
||||
const CalResourceDesc* cal() const { return &cal_; }
|
||||
|
||||
//! Returns the CAL resource handle
|
||||
gslMemObject gslResource() const { return gslRef_->gslResource(); }
|
||||
|
||||
//! Returns global memory offset
|
||||
uint64_t vmAddress() const { return gslResource()->getSurfaceAddress(); }
|
||||
|
||||
//! Checks if persistent memory can have a direct map
|
||||
bool isPersistentDirectMap() const;
|
||||
|
||||
/*! \brief Locks the resource and returns a physical pointer
|
||||
*
|
||||
* \note This operation stalls HW pipeline!
|
||||
*
|
||||
* \return Pointer to the physical memory
|
||||
*/
|
||||
void* map(
|
||||
VirtualGPU* gpu, //!< Virtual GPU device object
|
||||
uint flags = 0, //!< flags for the map operation
|
||||
// Optimization for multilayer map/unmap
|
||||
uint startLayer = 0, //!< Start layer for multilayer map
|
||||
uint numLayers = 0 //!< End layer for multilayer map
|
||||
);
|
||||
|
||||
//! Unlocks the resource if it was locked
|
||||
void unmap(
|
||||
VirtualGPU* gpu //!< Virtual GPU device object
|
||||
);
|
||||
|
||||
//! Marks the resource as busy
|
||||
void setBusy(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
GpuEvent calEvent //!< CAL event
|
||||
) const;
|
||||
|
||||
//! Wait for the resource
|
||||
void wait(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
bool waitOnBusyEngine = false//!< Wait only if engine has changed
|
||||
) const;
|
||||
|
||||
//! Performs host write to the resource GPU memory
|
||||
bool hostWrite(
|
||||
VirtualGPU* gpu, //!< Virtual GPU device object
|
||||
const void* hostPtr, //!< Host pointer to the SRC data
|
||||
const amd::Coord3D& origin, //!< Offsets for the update
|
||||
const amd::Coord3D& size, //!< The number of bytes to write
|
||||
uint flags = 0, //!< Map flags
|
||||
size_t rowPitch = 0, //!< Raw data row pitch
|
||||
size_t slicePitch = 0 //!< Raw data slice pitch
|
||||
);
|
||||
|
||||
//! Performs host read from the resource GPU memory
|
||||
bool hostRead(
|
||||
VirtualGPU* gpu, //!< Virtual GPU device object
|
||||
void* hostPtr, //!< Host pointer to the DST data
|
||||
const amd::Coord3D& origin, //!< Offsets for the update
|
||||
const amd::Coord3D& size, //!< The number of bytes to write
|
||||
size_t rowPitch = 0, //!< Raw data row pitch
|
||||
size_t slicePitch = 0 //!< Raw data slice pitch
|
||||
);
|
||||
|
||||
//! Warms up the rename list for this resource
|
||||
void warmUpRenames(VirtualGPU& gpu);
|
||||
|
||||
//! Gets the resource element size
|
||||
size_t elementSize() const { return elementSize_; }
|
||||
|
||||
//! Get the mapped address of this resource
|
||||
address data() const { return reinterpret_cast<address>(address_); }
|
||||
|
||||
//! Frees all allocated CAL memories and resources,
|
||||
//! associated with this objects. And also destroys all rename structures
|
||||
//! Note: doesn't destroy the object itself
|
||||
void free();
|
||||
|
||||
//! Return memory type
|
||||
MemoryType memoryType() const { return cal_.type_; }
|
||||
|
||||
//! Retunrs true if memory type matches specified
|
||||
bool isMemoryType(MemoryType memType) const;
|
||||
|
||||
//! Returns TRUE if resource was allocated as cacheable
|
||||
bool isCacheable() const
|
||||
{ return (isMemoryType(Remote) || isMemoryType(Pinned)) ? true : false; }
|
||||
|
||||
//! Returns alias memory object
|
||||
Resource* getAliasUAVBuffer(cmSurfFmt newFormat);
|
||||
|
||||
bool gslGLAcquire() ;
|
||||
bool gslGLRelease() ;
|
||||
|
||||
//! Returns HW state for the resource (used for images only)
|
||||
const void* hwState() const { return hwState_; }
|
||||
|
||||
//! Returns CPU HW SRD for the resource (used for images only)
|
||||
uint64_t hwSrd() const { return hwSrd_; }
|
||||
|
||||
protected:
|
||||
size_t elementSize_; //!< Size of a single element in bytes
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Resource(const Resource&);
|
||||
|
||||
//! Disable operator=
|
||||
Resource& operator=(const Resource&);
|
||||
|
||||
typedef std::vector<GslResourceReference*> RenameList;
|
||||
|
||||
//! Rename current resource
|
||||
bool rename(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
bool force = false //!< Force renaming
|
||||
);
|
||||
|
||||
//! Sets the rename as active
|
||||
void setActiveRename(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
GslResourceReference* rename //!< new active rename
|
||||
);
|
||||
|
||||
//! Gets the active rename
|
||||
bool getActiveRename(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
GslResourceReference** rename //!< Saved active rename
|
||||
);
|
||||
|
||||
/*! \brief Locks the resource with layers and returns a physical pointer
|
||||
*
|
||||
* \return Pointer to the physical memory
|
||||
*/
|
||||
void* mapLayers(
|
||||
VirtualGPU* gpu, //!< Virtual GPU device object
|
||||
CALuint flags = 0 //!< flags for the map operation
|
||||
);
|
||||
|
||||
//! Unlocks the resource with layers if it was locked
|
||||
void unmapLayers(
|
||||
VirtualGPU* gpu //!< Virtual GPU device object
|
||||
);
|
||||
|
||||
//! Calls GSL to map a resource
|
||||
bool gslMap(
|
||||
void** ptr, //!< Pointer to virtual address
|
||||
size_t* pitch, //!< Pitch value for the image
|
||||
gslMapAccessType flags, //!< Map flags
|
||||
gslMemObject resource //!< GSL memory object
|
||||
) const;
|
||||
|
||||
//! Uses GSL to unmap a resource
|
||||
bool gslUnmap(
|
||||
gslMemObject resource //!< GSL memory object
|
||||
) const;
|
||||
|
||||
//! Fress all GSL resources associated with OCL resource
|
||||
void gslFree() const;
|
||||
|
||||
const Device& gpuDevice_; //!< GPU device
|
||||
CalResourceDesc cal_; //!< CAL descriptor for this resource
|
||||
amd::Atomic<int> mapCount_; //!< Total number of maps
|
||||
void* address_; //!< Physical address of this resource
|
||||
size_t offset_; //!< Resource offset
|
||||
size_t curRename_; //!< Current active rename in the list
|
||||
RenameList renames_; //!< Rename resource list
|
||||
GslResourceReference* gslRef_; //!< GSL resource reference
|
||||
const Resource* viewOwner_; //!< GPU resource, which owns this view
|
||||
uint64_t hbOffset_; //!< Offset in the heap (virtual or real)
|
||||
uint64_t hbSize_; //!< Memory size
|
||||
uint64_t pinOffset_; //!< Pinned memory offset
|
||||
Resource* byteView_; //!< Byte view memory object
|
||||
Resource* shortView_; //!< Short view memory object
|
||||
gslMemObject glInterop_; //!< Original GL interop object
|
||||
void* glInteropMbRes_;//!< Mb Res handle
|
||||
CALResGLBufferType glType_; //!< GL interop type
|
||||
void* glPlatformContext_;
|
||||
void* glDeviceContext_;
|
||||
|
||||
// Optimization for multilayer map/unmap
|
||||
uint startLayer_; //!< Start layer for map/unmapLayer
|
||||
uint numLayers_; //!< Number of layers for map/unmapLayer
|
||||
CALuint mapFlags_; //!< Map flags for map/umapLayer
|
||||
|
||||
//! @note: This field is necessary for the thread safe release only
|
||||
VirtualGPU* gpu_; //!< Resource will be used only on this queue
|
||||
|
||||
uint32_t* hwState_; //!< HW state for image object
|
||||
uint64_t hwSrd_; //!< GPU pointer to HW SRD
|
||||
};
|
||||
|
||||
class ResourceCache : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
ResourceCache(size_t cacheSizeLimit)
|
||||
: lockCacheOps_("CAL resource cache", true)
|
||||
, cacheSize_(0)
|
||||
, cacheSizeLimit_(cacheSizeLimit)
|
||||
{}
|
||||
|
||||
//! Default destructor
|
||||
~ResourceCache();
|
||||
|
||||
//! Adds a CAL resource to the cache
|
||||
bool addCalResource(
|
||||
Resource::CalResourceDesc* desc, //!< CAL resource descriptor - cache key
|
||||
GslResourceReference* ref //!< CAL resource reference
|
||||
);
|
||||
|
||||
//! Finds a CAL resource from the cache
|
||||
GslResourceReference* findCalResource(
|
||||
Resource::CalResourceDesc* desc //!< CAL resource descriptor - cache key
|
||||
);
|
||||
|
||||
//! Destroys cache
|
||||
bool free(size_t minCacheEntries = 0);
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
ResourceCache(const ResourceCache&);
|
||||
|
||||
//! Disable operator=
|
||||
ResourceCache& operator=(const ResourceCache&);
|
||||
|
||||
//! Gets resource size in bytes
|
||||
size_t getResourceSize(Resource::CalResourceDesc* desc);
|
||||
|
||||
//! Removes one last entry from the cache
|
||||
void removeLast();
|
||||
|
||||
amd::Monitor lockCacheOps_; //!< Lock to serialise cache access
|
||||
|
||||
size_t cacheSize_; //!< Current cache size in bytes
|
||||
size_t cacheSizeLimit_; //!< Cache size limit in bytes
|
||||
|
||||
//! CAL resource cache
|
||||
std::list<std::pair<Resource::CalResourceDesc*, GslResourceReference*> > resCache_;
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPURESOURCE_HPP_*/
|
||||
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUSCHED_HPP_
|
||||
#define GPUSCHED_HPP_
|
||||
|
||||
#include "newcore.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
//! AmdAqlWrap slot state
|
||||
enum AqlWrapState {
|
||||
AQL_WRAP_FREE = 0,
|
||||
AQL_WRAP_RESERVED,
|
||||
AQL_WRAP_READY,
|
||||
AQL_WRAP_MARKER,
|
||||
AQL_WRAP_BUSY,
|
||||
AQL_WRAP_DONE
|
||||
};
|
||||
|
||||
struct AmdVQueueHeader {
|
||||
uint32_t aql_slot_num; //!< [LRO/SRO] The total number of the AQL slots (multiple of 64).
|
||||
uint32_t event_slot_num; //!< [LRO] The number of kernel events in the events buffer
|
||||
uint64_t event_slot_mask; //!< [LRO] A pointer to the allocation bitmask array for the events
|
||||
uint64_t event_slots; //!< [LRO] Pointer to a buffer for the events.
|
||||
// Array of event_slot_num entries of AmdEvent
|
||||
uint64_t aql_slot_mask; //!< [LRO/SRO]A pointer to the allocation bitmask for aql_warp slots
|
||||
uint32_t command_counter; //!< [LRW] The global counter for the submitted commands into the queue
|
||||
uint32_t wait_size; //!< [LRO] The wait list size (in clk_event_t)
|
||||
uint32_t arg_size; //!< [LRO] The size of argument buffer (in bytes)
|
||||
uint32_t reserved0; //!< For the future usage
|
||||
uint64_t kernel_table; //!< [LRO] Pointer to an array with all kernel objects (ulong for each entry)
|
||||
uint32_t reserved[2]; //!< For the future usage
|
||||
};
|
||||
|
||||
struct AmdAqlWrap {
|
||||
uint32_t state; //!< [LRW/SRW] The current state of the AQL wrapper: FREE, RESERVED, READY,
|
||||
// MARKER, BUSY and DONE. The block could be returned back to a free state.
|
||||
uint32_t enqueue_flags; //!< [LWO/SRO] Contains the flags for the kernel execution start
|
||||
uint32_t command_id; //!< [LWO/SRO] The unique command ID
|
||||
uint32_t child_counter; //!< [LRW/SRW] Counter that determine the launches of child kernels.
|
||||
// It’s incremented on the
|
||||
// start and decremented on the finish. The parent kernel can be considered as
|
||||
// done when the value is 0 and the state is DONE
|
||||
uint64_t completion; //!< [LWO/SRO] CL event for the current execution (clk_event_t)
|
||||
uint64_t parent_wrap; //!< [LWO/SRO] Pointer to the parent AQL wrapper (AmdAqlWrap*)
|
||||
uint64_t wait_list; //!< [LRO/SRO] Pointer to an array of clk_event_t objects (64 bytes default)
|
||||
uint32_t wait_num; //!< [LWO/SRO] The number of cl_event_wait objects
|
||||
uint32_t reserved[5]; //!< For the future usage
|
||||
HsaAqlDispatchPacket aql; //!< [LWO/SRO] AQL packet – 64 bytes AQL packet
|
||||
};
|
||||
|
||||
struct AmdEvent {
|
||||
uint32_t state; //!< [LRO/SRW] Event state: START, END, COMPLETE
|
||||
uint32_t counter; //!< [LRW] Event retain/release counter. 0 means the event is free
|
||||
uint64_t timer[3]; //!< [LRO/SWO] Timer values for profiling for each state
|
||||
};
|
||||
|
||||
struct SchedulerParam {
|
||||
uint32_t signal; //!< Signal to stop the child queue(address must be 16 bytes aligned)
|
||||
uint32_t eng_clk; //!< Engine clock in Mhz
|
||||
uint64_t hw_queue; //!< Address to HW queue
|
||||
uint64_t hsa_queue; //!< Address to HSA dummy queue
|
||||
uint32_t launch; //!< Launch semaphore for the scheduler threads
|
||||
uint32_t scratchSize; //!< Scratch buffer size
|
||||
uint64_t scratch; //!< GPU address to the scratch buffer
|
||||
uint32_t numMaxWaves; //!< The max number of possible waves
|
||||
uint32_t reserved; //!< reserved
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,467 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
namespace gpu {
|
||||
|
||||
#define SCHEDULER_KERNEL(...) #__VA_ARGS__
|
||||
|
||||
const char* SchedulerSourceCode = SCHEDULER_KERNEL(
|
||||
\n
|
||||
|
||||
//! AmdAqlWrap slot state
|
||||
enum AqlWrapState {
|
||||
AQL_WRAP_FREE = 0,
|
||||
AQL_WRAP_RESERVED,
|
||||
AQL_WRAP_READY,
|
||||
AQL_WRAP_MARKER,
|
||||
AQL_WRAP_BUSY,
|
||||
AQL_WRAP_DONE
|
||||
};
|
||||
|
||||
//! Profiling states
|
||||
enum ProfilingState {
|
||||
PROFILING_COMMAND_START = 0,
|
||||
PROFILING_COMMAND_END,
|
||||
PROFILING_COMMAND_COMPLETE
|
||||
};
|
||||
|
||||
typedef struct _HsaAqlDispatchPacket {
|
||||
uint mix;
|
||||
ushort workgroup_size[3];
|
||||
ushort reserved2;
|
||||
uint grid_size[3];
|
||||
uint private_segment_size_bytes;
|
||||
uint group_segment_size_bytes;
|
||||
ulong kernel_object_address;
|
||||
ulong kernel_arg_address;
|
||||
ulong reserved3;
|
||||
ulong completion_signal;
|
||||
} HsaAqlDispatchPacket;
|
||||
|
||||
typedef struct _AmdVQueueHeader {
|
||||
uint aql_slot_num; //!< [LRO/SRO] The total number of the AQL slots (multiple of 64).
|
||||
uint event_slot_num; //!< [LRO] The number of kernel events in the events buffer
|
||||
ulong event_slot_mask; //!< [LRO] A pointer to the allocation bitmask array for the events
|
||||
ulong event_slots; //!< [LRO] Pointer to a buffer for the events.
|
||||
// Array of event_slot_num entries of AmdEvent
|
||||
ulong aql_slot_mask; //!< [LRO/SRO]A pointer to the allocation bitmask for aql_warp slots
|
||||
uint command_counter; //!< [LRW] The global counter for the submitted commands into the queue
|
||||
uint wait_size; //!< [LRO] The wait list size (in clk_event_t)
|
||||
uint arg_size; //!< [LRO] The size of argument buffer (in bytes)
|
||||
uint reserved0; //!< For the future usage
|
||||
ulong kernel_table; //!< [LRO] Pointer to an array with all kernel objects (ulong for each entry)
|
||||
uint reserved[2]; //!< For the future usage
|
||||
} AmdVQueueHeader;
|
||||
|
||||
typedef struct _AmdAqlWrap {
|
||||
uint state; //!< [LRW/SRW] The current state of the AQL wrapper: FREE, RESERVED, READY,
|
||||
// MARKER, BUSY and DONE. The block could be returned back to a free state.
|
||||
uint enqueue_flags; //!< [LWO/SRO] Contains the flags for the kernel execution start –
|
||||
// (kernel_enqueue_flags_t)
|
||||
// CLK_ENQUEUE_FLAGS_NO_WAIT – we just start processing
|
||||
// CLK_ENQUEUE_FLAGS_WAIT_KERNEL – check if parent_wrap->state is done and then start processing
|
||||
// CLK_ENQUEUE_FLAGS_WAIT_WORK_GROUP - currently == WAIT_KERNEL
|
||||
uint command_id; //!< [LWO/SRO] The unique command ID
|
||||
uint child_counter; //!< [LRW/SRW] Counter that determine the launches of child kernels.
|
||||
// It’s incremented on the
|
||||
// start and decremented on the finish. The parent kernel can be considered as
|
||||
// done when the value is 0 and the state is DONE
|
||||
ulong completion; //!< [LWO/SRO] CL event for the current execution (clk_event_t)
|
||||
ulong parent_wrap; //!< [LWO/SRO] Pointer to the parent AQL wrapper (AmdAqlWrap*)
|
||||
ulong wait_list; //!< [LRO/SRO] Pointer to an array of clk_event_t objects (64 bytes default)
|
||||
uint wait_num; //!< [LWO/SRO] The number of cl_event_wait objects
|
||||
uint reserved[5]; //!< For the future usage
|
||||
HsaAqlDispatchPacket aql; //!< [LWO/SRO] AQL packet – 64 bytes AQL packet
|
||||
} AmdAqlWrap;
|
||||
|
||||
typedef struct _AmdEvent {
|
||||
uint state; //!< [LRO/SRW] Event state: START, END, COMPLETE
|
||||
uint counter; //!< [LRW] Event retain/release counter. 0 means the event is free
|
||||
ulong timer[3]; //!< [LRO/SWO] Timer values for profiling for each state
|
||||
} AmdEvent;
|
||||
|
||||
typedef struct _SchedulerParam {
|
||||
uint signal; //!< Signal to stop the child queue
|
||||
uint eng_clk; //!< Engine clock in Mhz
|
||||
ulong hw_queue; //!< Address to HW queue
|
||||
ulong hsa_queue; //!< Address to HSA dummy queue
|
||||
uint launch; //!< Child launch status
|
||||
uint scratchSize; //!< Scratch buffer size
|
||||
ulong scratch; //!< GPU address to the scratch buffer
|
||||
uint numMaxWaves; //!< Num max waves on the asic
|
||||
uint reserved; //!< Reserved
|
||||
} SchedulerParam;
|
||||
|
||||
typedef struct _HwDispatch {
|
||||
uint startExe; // REWIND execution
|
||||
uint condExe0; // 0xC0032200 -- TYPE 3, COND_EXEC
|
||||
uint condExe1; // 0x00000204 ----
|
||||
uint condExe2; // 0x00000000 ----
|
||||
uint condExe3; // 0x00000000 ----
|
||||
uint condExe4; // 0x00000000 ----
|
||||
uint packet0; // 0xC0067602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (6 values)
|
||||
uint offset0; // 0x00000204 ---- OFFSET
|
||||
uint startX; // 0x00000000 ---- COMPUTE_START_X: START = 0x0
|
||||
uint startY; // 0x00000000 ---- COMPUTE_START_Y: START = 0x0
|
||||
uint startZ; // 0x00000000 ---- COMPUTE_START_Z: START = 0x0
|
||||
uint wrkGrpSizeX; // 0x00000000 ---- COMPUTE_NUM_THREAD_X: NUM_THREAD_FULL = 0x0, NUM_THREAD_PARTIAL = 0x0
|
||||
uint wrkGrpSizeY; // 0x00000000 ---- COMPUTE_NUM_THREAD_Y: NUM_THREAD_FULL = 0x0, NUM_THREAD_PARTIAL = 0x0
|
||||
uint wrkGrpSizeZ; // 0x00000000 ---- COMPUTE_NUM_THREAD_Z: NUM_THREAD_FULL = 0x0, NUM_THREAD_PARTIAL = 0x0
|
||||
uint packet1; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offset1; // 0x0000020C ---- OFFSET
|
||||
uint isaLo; // 0x00000000 ---- COMPUTE_PGM_LO: DATA = 0x0
|
||||
uint isaHi; // 0x00000000 ---- COMPUTE_PGM_HI: DATA = 0x0, INST_ATC__CI__VI = 0x0
|
||||
uint packet2; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offset2; // 0x00000212 ---- OFFSET
|
||||
uint resource1; // 0x00000000 ---- COMPUTE_PGM_RSRC1: VGPRS = 0x0, SGPRS = 0x0, PRIORITY = 0x0, FLOAT_MODE = 0x0, PRIV = 0x0, DX10_CLAMP = 0x0, DEBUG_MODE = 0x0, IEEE_MODE = 0x0, BULKY__CI__VI = 0x0, CDBG_USER__CI__VI = 0x0
|
||||
uint resource2; // 0x00000000 ---- COMPUTE_PGM_RSRC2: SCRATCH_EN = 0x0, USER_SGPR = 0x0, TRAP_PRESENT = 0x0, TGID_X_EN = 0x0, TGID_Y_EN = 0x0, TGID_Z_EN = 0x0, TG_SIZE_EN = 0x0, TIDIG_COMP_CNT = 0x0, EXCP_EN_MSB__CI__VI = 0x0, LDS_SIZE = 0x0, EXCP_EN = 0x0
|
||||
uint packet3; // 0xC0067602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (6 values)
|
||||
uint offset3; // 0x00000215 ---- OFFSET
|
||||
uint pad31; // 0x00000000 ---- COMPUTE_RESOURCE_LIMITS: WAVES_PER_SH = 0x0, TG_PER_CU = 0x0, LOCK_THRESHOLD = 0x0, SIMD_DEST_CNTL = 0x0, FORCE_SIMD_DIST__CI__VI = 0x0, CU_GROUP_COUNT__CI__VI = 0x0
|
||||
uint pad32; // 0xFFFFFFFF ---- COMPUTE_STATIC_THREAD_MGMT_SE0: SH0_CU_EN = 0xFFFF, SH1_CU_EN = 0xFFFF
|
||||
uint pad33; // 0xFFFFFFFF ---- COMPUTE_STATIC_THREAD_MGMT_SE1: SH0_CU_EN = 0xFFFF, SH1_CU_EN = 0xFFFF
|
||||
uint ringSize; // 0x00000000 ---- COMPUTE_TMPRING_SIZE: WAVES = 0x0, WAVESIZE = 0x0
|
||||
uint pad34; // 0xFFFFFFFF ---- COMPUTE_STATIC_THREAD_MGMT_SE2__CI__VI: SH0_CU_EN = 0xFFFF, SH1_CU_EN = 0xFFFF
|
||||
uint pad35; // 0xFFFFFFFF ---- COMPUTE_STATIC_THREAD_MGMT_SE3__CI__VI: SH0_CU_EN = 0xFFFF, SH1_CU_EN = 0xFFFF
|
||||
uint user0; // 0xC0047602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (4 values)
|
||||
uint offsUser0; // 0x00000240 ---- OFFSET
|
||||
uint scratchLo; // 0x00000000 ---- COMPUTE_USER_DATA_0: DATA = 0x0
|
||||
uint scratchHi; // 0x80000000 ---- COMPUTE_USER_DATA_1: DATA = 0x80000000
|
||||
uint scratchSize; // 0x00000000 ---- COMPUTE_USER_DATA_2: DATA = 0x0
|
||||
uint padUser; // 0x00EA7FAC ---- COMPUTE_USER_DATA_3: DATA = 0xEA7FAC
|
||||
uint user1; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offsUser1; // 0x00000244 ---- OFFSET
|
||||
uint aqlPtrLo; // 0x00000000 ---- COMPUTE_USER_DATA_4: DATA = 0x0
|
||||
uint aqlPtrHi; // 0x00000000 ---- COMPUTE_USER_DATA_5: DATA = 0x0
|
||||
uint user2; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offsUser2; // 0x00000246 ---- OFFSET
|
||||
uint hsaQueueLo; // 0x00000000 ---- COMPUTE_USER_DATA_6: DATA = 0x0
|
||||
uint hsaQueueHi; // 0x00000000 ---- COMPUTE_USER_DATA_7: DATA = 0x0
|
||||
uint user3; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offsUser3; // 0x00000246 ---- OFFSET
|
||||
uint argsLo; // 0x00000000 ---- COMPUTE_USER_DATA_8: DATA = 0x0
|
||||
uint argsHi; // 0x00000000 ---- COMPUTE_USER_DATA_9: DATA = 0x0
|
||||
uint copyData; // 0xC0044000 -- TYPE 3, COPY_DATA
|
||||
uint copyDataFlags; // 0x00000405 ---- srcSel 0x5, destSel 0x4, countSel 0x0, wrConfirm 0x0, engineSel 0x0
|
||||
uint scratchAddrLo; // 0x000201C4 ---- srcAddressLo
|
||||
uint scratchAddrHi; // 0x00000000 ---- srcAddressHi
|
||||
uint shPrivateLo; // 0x00002580 ---- dstAddressLo
|
||||
uint shPrivateHi; // 0x00000000 ---- dstAddressHi
|
||||
uint user4; // 0xC0027602 -- TYPE 3, SET_SH_REG, TYPE:COMPUTE (2 values)
|
||||
uint offsUser4; // 0x00000248 ---- OFFSET
|
||||
uint privOffs; // 0x00000000 ---- COMPUTE_USER_DATA_10: DATA = 0x0
|
||||
uint privSize; // 0x00000030 ---- COMPUTE_USER_DATA_11: DATA = 0x30
|
||||
uint packet4; // 0xC0031502 -- TYPE 3, DISPATCH_DIRECT, TYPE:COMPUTE
|
||||
uint glbSizeX; // 0x00000000
|
||||
uint glbSizeY; // 0x00000000
|
||||
uint glbSizeZ; // 0x00000000
|
||||
uint padd41; // 0x00000021
|
||||
} HwDispatch;
|
||||
|
||||
const uint ResumeExecution = 0x80000000; // 0x81000000
|
||||
const uint StallExecution = 0x00000000; // 0x01000000
|
||||
const uint WavefrontSize = 64;
|
||||
const uint MaxWaveSize = 0x400;
|
||||
|
||||
void dispatch(
|
||||
volatile __global HwDispatch* dispatch,
|
||||
__global HsaAqlDispatchPacket* aqlPkt,
|
||||
uint scratchSize,
|
||||
uint numMaxWaves,
|
||||
ulong scratch,
|
||||
ulong hsaQueue)
|
||||
{
|
||||
const uint UsrRegOffset = 0x240;
|
||||
const uint Pm4Nop = 0xC0001002;
|
||||
const uint Pm4UserRegs = 0xC0007602;
|
||||
const uint Pm4CopyReg = 0xC0044000;
|
||||
|
||||
// Wait for CP idle isn't necessary if CP waits for child
|
||||
// while (atomic_and(&dispatch->startExe, 0xffffffff) != StallExecution) {}
|
||||
|
||||
uint usrRegCnt = 0;
|
||||
|
||||
dispatch->wrkGrpSizeX = aqlPkt->workgroup_size[0];
|
||||
dispatch->wrkGrpSizeY = aqlPkt->workgroup_size[1];
|
||||
dispatch->wrkGrpSizeZ = aqlPkt->workgroup_size[2];
|
||||
// ISA address
|
||||
__global uchar* kernelObj = (__global uchar*)aqlPkt->kernel_object_address;
|
||||
ulong isa = aqlPkt->kernel_object_address + *((__global uint*)(kernelObj + 0x10));
|
||||
dispatch->isaLo = (uint)(isa >> 8);
|
||||
dispatch->isaHi = (uint)(isa >> 40);
|
||||
|
||||
// Program PGM resource registers
|
||||
dispatch->resource1 = *((__global uint*)(kernelObj + 0x30));
|
||||
dispatch->resource2 = *((__global uint*)(kernelObj + 0x34));
|
||||
uint flags = *((__global uint*)(kernelObj + 0x38));
|
||||
uint privateSize = *((__global uint*)(kernelObj + 0x50));
|
||||
|
||||
uint ldsSize = aqlPkt->group_segment_size_bytes +
|
||||
*((__global uint*)(kernelObj + 0x54));
|
||||
// Align up the LDS blocks 128 * 4(in DWORDs)
|
||||
uint ldsBlocks = (ldsSize + 511) >> 9;
|
||||
dispatch->resource2 |= (ldsBlocks << 15);
|
||||
|
||||
// Workaround for compiler bug
|
||||
dispatch->scratchLo = (flags & 1);
|
||||
// privSegEna = (flags & 1);
|
||||
if (flags & 0x1) {
|
||||
uint waveSize = privateSize * WavefrontSize;
|
||||
// 256 DWRODs is the minimum for SQ
|
||||
waveSize = max(MaxWaveSize, waveSize);
|
||||
uint numWaves = scratchSize / waveSize;
|
||||
numWaves = min(numWaves, numMaxWaves);
|
||||
dispatch->ringSize = numWaves;
|
||||
dispatch->ringSize |= (waveSize >> 10) << 12;
|
||||
dispatch->user0 = Pm4UserRegs | (4 << 16);
|
||||
dispatch->scratchLo = (uint)scratch;
|
||||
dispatch->scratchHi = ((uint)(scratch >> 32)) | 0x80000000; // Enables swizzle
|
||||
dispatch->scratchSize = scratchSize;
|
||||
usrRegCnt += 4;
|
||||
}
|
||||
else {
|
||||
dispatch->ringSize = 0;
|
||||
dispatch->user0 = Pm4Nop | (4 << 16);
|
||||
}
|
||||
|
||||
// dispatchEna = (flags & 0x2);
|
||||
dispatch->user1 = (flags & 0x2) ? (Pm4UserRegs | (2 << 16)) : (Pm4Nop | (2 << 16));
|
||||
dispatch->offsUser1 = UsrRegOffset + usrRegCnt;
|
||||
usrRegCnt += (flags & 0x2) ? 2 : 0;
|
||||
ulong gpuAqlPtr = (ulong)aqlPkt;
|
||||
dispatch->aqlPtrLo = (uint)gpuAqlPtr;
|
||||
dispatch->aqlPtrHi = (uint)(gpuAqlPtr >> 32);
|
||||
|
||||
// queuePtr = (flags & 0x4);
|
||||
if (flags & 0x4) {
|
||||
dispatch->user2 = Pm4UserRegs | (2 << 16);
|
||||
dispatch->offsUser2 = UsrRegOffset + usrRegCnt;
|
||||
usrRegCnt += 2;
|
||||
dispatch->hsaQueueLo = (uint)hsaQueue;
|
||||
dispatch->hsaQueueHi = (uint)(hsaQueue >> 32);
|
||||
}
|
||||
else {
|
||||
dispatch->user2 = Pm4Nop | (2 << 16);
|
||||
}
|
||||
|
||||
// kernelArgEna = (flags & 0x8);
|
||||
dispatch->user3 = (flags & 0x8) ? (Pm4UserRegs | (2 << 16)) : (Pm4Nop | (2 << 16));
|
||||
dispatch->offsUser3 = UsrRegOffset + usrRegCnt;
|
||||
usrRegCnt += (flags & 0x8) ? 2 : 0;
|
||||
dispatch->argsLo = (uint)aqlPkt->kernel_arg_address;
|
||||
dispatch->argsHi = (uint)(aqlPkt->kernel_arg_address >> 32);
|
||||
|
||||
// flatScratchEna = (flags & 0x20);
|
||||
if (flags & 0x20) {
|
||||
dispatch->copyData = Pm4CopyReg;
|
||||
dispatch->scratchAddrLo = (uint)(scratch >> 16);
|
||||
dispatch->offsUser4 = UsrRegOffset + usrRegCnt;
|
||||
dispatch->privSize = privateSize;
|
||||
}
|
||||
else {
|
||||
dispatch->copyData = Pm4Nop | (8 << 16);
|
||||
}
|
||||
|
||||
dispatch->glbSizeX = aqlPkt->grid_size[0];
|
||||
dispatch->glbSizeY = aqlPkt->grid_size[1];
|
||||
dispatch->glbSizeZ = aqlPkt->grid_size[2];
|
||||
barrier(CLK_GLOBAL_MEM_FENCE);
|
||||
|
||||
// Resume the execution
|
||||
dispatch->startExe = ResumeExecution;
|
||||
}
|
||||
|
||||
bool
|
||||
checkWaitEvents(__global AmdEvent* events, uint numEvents)
|
||||
{
|
||||
for (uint i = 0; i < numEvents; ++i) {
|
||||
if (atomic_and(&events[i].state, 0xffffffff) != CL_COMPLETE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// release slot in a bitmask controlled resource i is the slot number
|
||||
static inline void
|
||||
release_slot(__global uint * restrict mask, uint i)
|
||||
{
|
||||
/* uint b = ~(1UL << (i & 0x1f)); */
|
||||
uint b = ~amd_bfm(1U, i);
|
||||
__global atomic_uint *p = (__global atomic_uint *)(mask + (i >> 5));
|
||||
uint vv;
|
||||
uint v = atomic_load_explicit(p, memory_order_acquire, memory_scope_device);
|
||||
for (;;) {
|
||||
vv = v & b;
|
||||
if (atomic_compare_exchange_strong_explicit(p, &v, vv,
|
||||
memory_order_acq_rel, memory_order_acquire, memory_scope_device)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint
|
||||
min_command(uint slot_num, __global AmdAqlWrap* wraps)
|
||||
{
|
||||
uint minCommand = 0xffffffff;
|
||||
for (uint idx = 0; idx < slot_num; ++idx) {
|
||||
__global AmdAqlWrap* disp = (__global AmdAqlWrap*)&wraps[idx];
|
||||
uint slotState = atomic_load_explicit((__global atomic_uint*)(&disp->state),
|
||||
memory_order_acquire, memory_scope_device);
|
||||
if ((slotState != AQL_WRAP_FREE) && (slotState != AQL_WRAP_RESERVED)) {
|
||||
minCommand = min(disp->command_id, minCommand);
|
||||
}
|
||||
}
|
||||
return minCommand;
|
||||
}
|
||||
|
||||
extern ulong __hsail_get_clock(); // Declaration is required
|
||||
|
||||
__kernel void
|
||||
scheduler(
|
||||
__global AmdVQueueHeader* queue,
|
||||
__global SchedulerParam* params,
|
||||
uint paramIdx)
|
||||
{
|
||||
__global SchedulerParam* param = ¶ms[paramIdx];
|
||||
volatile __global HwDispatch* hwDisp =
|
||||
(volatile __global HwDispatch*)param->hw_queue;
|
||||
__global uint* signal = (__global uint*)(¶m->signal);
|
||||
__global AmdAqlWrap* wraps = (__global AmdAqlWrap*)&queue[1];
|
||||
__global uint* amask = (__global uint *)queue->aql_slot_mask;
|
||||
|
||||
uint launch = 0;
|
||||
uint loop;
|
||||
|
||||
do {
|
||||
uint mask = atomic_load_explicit((__global atomic_uint*)(&amask[get_group_id(0)]),
|
||||
memory_order_acquire, memory_scope_device);
|
||||
|
||||
if (mask != 0) {
|
||||
int baseIdx = get_group_id(0) * 32;
|
||||
for (int idx = baseIdx + 31 - clz(mask); (idx >= baseIdx) && (launch == 0); --idx) {
|
||||
__global AmdAqlWrap* disp = (__global AmdAqlWrap*)&wraps[idx];
|
||||
uint slotState = atomic_load_explicit((__global atomic_uint*)(&disp->state),
|
||||
memory_order_acquire, memory_scope_device);
|
||||
__global AmdAqlWrap* parent = (__global AmdAqlWrap*)(disp->parent_wrap);
|
||||
__global AmdEvent* event = (__global AmdEvent*)(disp->completion);
|
||||
|
||||
// Check if the current slot is ready for processing
|
||||
if (slotState == AQL_WRAP_READY) {
|
||||
if (launch == 0) {
|
||||
launch = atomic_load_explicit((__global atomic_uint*)¶m->launch,
|
||||
memory_order_acquire, memory_scope_device);
|
||||
}
|
||||
if (launch == 0) {
|
||||
// Attempt to find a new disaptch if nothing was launched yet
|
||||
uint parentState = atomic_load_explicit(
|
||||
(__global atomic_uint*)(&parent->state),
|
||||
memory_order_acquire, memory_scope_device);
|
||||
|
||||
// Check the launch flags
|
||||
if (((disp->enqueue_flags == CLK_ENQUEUE_FLAGS_WAIT_KERNEL) ||
|
||||
(disp->enqueue_flags == CLK_ENQUEUE_FLAGS_WAIT_WORK_GROUP)) &&
|
||||
(parentState != AQL_WRAP_DONE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the command has any the wait events
|
||||
if (disp->wait_num != 0) {
|
||||
// Check if the wait list is COMPLETE
|
||||
launch = checkWaitEvents(
|
||||
(__global AmdEvent*)(disp->wait_list), disp->wait_num);
|
||||
}
|
||||
else {
|
||||
launch = 1;
|
||||
}
|
||||
uint tmp = 0;
|
||||
if (atomic_compare_exchange_strong_explicit(
|
||||
(__global atomic_uint*)¶m->launch, &tmp, launch,
|
||||
memory_order_acq_rel, memory_order_acq_rel, memory_scope_device)) {
|
||||
if (event != 0) {
|
||||
event->timer[PROFILING_COMMAND_START] =
|
||||
(__hsail_get_clock() * 1000) / (ulong)param->eng_clk;
|
||||
}
|
||||
// Launch child kernel ....
|
||||
dispatch(hwDisp, &disp->aql, param->scratchSize, param->numMaxWaves,
|
||||
param->scratch, param->hsa_queue);
|
||||
disp->state = AQL_WRAP_BUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (slotState == AQL_WRAP_MARKER) {
|
||||
bool complete = false;
|
||||
if (disp->wait_num == 0) {
|
||||
uint minCommand = min_command(queue->aql_slot_num, wraps);
|
||||
if (disp->command_id == minCommand) {
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Check if the wait list is COMPLETE
|
||||
if (checkWaitEvents(
|
||||
(__global AmdEvent*)(disp->wait_list), disp->wait_num)) {
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
if (complete) {
|
||||
// Decrement the child execution counter on the parent
|
||||
atomic_fetch_sub_explicit(
|
||||
(__global atomic_uint*)&parent->child_counter,
|
||||
1, memory_order_acq_rel, memory_scope_device);
|
||||
event->state = CL_COMPLETE;
|
||||
disp->state = AQL_WRAP_FREE;
|
||||
release_slot(amask, idx);
|
||||
}
|
||||
}
|
||||
else if (slotState == AQL_WRAP_DONE) {
|
||||
// Was CL_EVENT requested?
|
||||
if (event != 0) {
|
||||
// The current dispatch doesn't have any outstanding children
|
||||
if (disp->child_counter == 0) {
|
||||
event->state = CL_COMPLETE;
|
||||
event->timer[PROFILING_COMMAND_END] =
|
||||
event->timer[PROFILING_COMMAND_COMPLETE] =
|
||||
(__hsail_get_clock() * 1000) / (ulong)param->eng_clk;
|
||||
}
|
||||
else {
|
||||
event->timer[PROFILING_COMMAND_END] =
|
||||
(__hsail_get_clock() * 1000) / (ulong)param->eng_clk;
|
||||
}
|
||||
}
|
||||
// The current dispatch doesn't have any outstanding children
|
||||
if (disp->child_counter == 0) {
|
||||
// Decrement the child execution counter on the parent
|
||||
atomic_fetch_sub_explicit(
|
||||
(__global atomic_uint*)&parent->child_counter,
|
||||
1, memory_order_acq_rel, memory_scope_device);
|
||||
disp->state = AQL_WRAP_FREE;
|
||||
release_slot(amask, idx);
|
||||
}
|
||||
}
|
||||
else if (slotState == AQL_WRAP_BUSY) {
|
||||
disp->state = AQL_WRAP_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
barrier(CLK_GLOBAL_MEM_FENCE);
|
||||
|
||||
launch = atomic_load_explicit((__global atomic_uint*)¶m->launch,
|
||||
memory_order_acquire, memory_scope_device);
|
||||
|
||||
loop = atomic_load_explicit((__global atomic_uint*)signal,
|
||||
memory_order_acquire, memory_scope_device);
|
||||
|
||||
} while ((launch == 0) && (loop == 1));
|
||||
|
||||
if (loop == 0) {
|
||||
atomic_or(&hwDisp->startExe, ResumeExecution);
|
||||
}
|
||||
}
|
||||
\n
|
||||
\n
|
||||
);
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,479 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
#include "acl.h"
|
||||
#define R900_BUILD 1
|
||||
#include "SCShadersR800.h"
|
||||
#include "r8xx_r9xx_merged__offset.h"
|
||||
#include "r8xx_r9xx_merged__typedef.h"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
#define NUM_R800_CS_INFOS (0x22+SC_R800_MAX_UAV+ \
|
||||
3+ /* globalReturnBuffer flag plus numUavs and numGlobalReturnBuffers */ \
|
||||
1+ /* extendedCaching flag */ \
|
||||
3+ /* globalReturnBuffer sizes for dword, shorts and bytes */ \
|
||||
3*SC_R800_MAX_UAV+ /* offsetmap, cached and uncached fetch consts */ \
|
||||
2*SC_R800_MAX_UAV+ /* 64- and 128-bit cached fetch consts */ \
|
||||
2*R800_GLOBAL_RTN_BUF_LAST /* global return buffer fetch consts and type */ )
|
||||
|
||||
struct Options {
|
||||
uint numClauseTemps_;
|
||||
uint numGPRs_;
|
||||
uint numThreads_;
|
||||
uint numStackEntries_;
|
||||
uint ldsSize_;
|
||||
|
||||
Options(CALtarget target) {
|
||||
numClauseTemps_ = 4;
|
||||
|
||||
switch (target) {
|
||||
case CAL_TARGET_DEVASTATOR:
|
||||
case CAL_TARGET_SCRAPPER:
|
||||
case CAL_TARGET_CAYMAN:
|
||||
case CAL_TARGET_KAUAI:
|
||||
numClauseTemps_ = 0;
|
||||
numStackEntries_ = 512;
|
||||
numThreads_ = 248;
|
||||
break;
|
||||
case CAL_TARGET_SUPERSUMO:
|
||||
case CAL_TARGET_TURKS:
|
||||
case CAL_TARGET_REDWOOD:
|
||||
numStackEntries_ = 256;
|
||||
numThreads_ = 248;
|
||||
break;
|
||||
case CAL_TARGET_WRESTLER:
|
||||
case CAL_TARGET_SUMO:
|
||||
case CAL_TARGET_CAICOS:
|
||||
case CAL_TARGET_CEDAR:
|
||||
numStackEntries_ = 256;
|
||||
numThreads_ = 192;
|
||||
break;
|
||||
case CAL_TARGET_CYPRESS:
|
||||
case CAL_TARGET_BARTS:
|
||||
case CAL_TARGET_JUNIPER:
|
||||
numStackEntries_ = 512;
|
||||
numThreads_ = 248;
|
||||
break;
|
||||
default:
|
||||
numStackEntries_ = 512;
|
||||
numThreads_ = 248;
|
||||
LogError("Unknown ASIC type");
|
||||
}
|
||||
|
||||
numGPRs_ = 256 - 2 * numClauseTemps_;
|
||||
ldsSize_ = 32*1024;
|
||||
}
|
||||
private:
|
||||
Options();
|
||||
Options(const Options&);
|
||||
Options& operator=(const Options&);
|
||||
};
|
||||
|
||||
static const uint UncachedFetchConst[SC_R800_MAX_UAV] =
|
||||
{ 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 173 };
|
||||
|
||||
static const uint CachedFetchConst[SC_R800_MAX_UAV] =
|
||||
{ 144, 145, 146, 148, 149, 150, 151, 152, 0, 0, 0, 153 };
|
||||
|
||||
static const uint GlobalReturnFetchConst[R800_GLOBAL_RTN_BUF_LAST] =
|
||||
{ 165, 166, 167, 168, 169, 170, 171, 172 };
|
||||
|
||||
static const uint GlobalReturnBufferType[R800_GLOBAL_RTN_BUF_LAST] =
|
||||
{ AMU_ABI_UAV_FORMAT_TYPELESS, AMU_ABI_UAV_FORMAT_FLOAT,
|
||||
AMU_ABI_UAV_FORMAT_UNORM, AMU_ABI_UAV_FORMAT_SNORM, AMU_ABI_UAV_FORMAT_UINT,
|
||||
AMU_ABI_UAV_FORMAT_SINT, AMU_ABI_UAV_FORMAT_SHORT, AMU_ABI_UAV_FORMAT_BYTE };
|
||||
|
||||
static const uint CachedFetchConst64[SC_R800_MAX_UAV] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 174 };
|
||||
|
||||
static const uint CachedFetchConst128[SC_R800_MAX_UAV] =
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 175 };
|
||||
|
||||
bool
|
||||
NullKernel::r800CreateHwInfo(const void* shader, AMUabiAddEncoding& encoding)
|
||||
{
|
||||
CALProgramInfoEntry* newInfos;
|
||||
const Options options(nullDev().calTarget());
|
||||
uint i = 0;
|
||||
uint numShaderEngines = 1;
|
||||
if ((nullDev().calTarget() == CAL_TARGET_CAYMAN) ||
|
||||
(nullDev().calTarget() == CAL_TARGET_CYPRESS) ||
|
||||
(nullDev().calTarget() == CAL_TARGET_BARTS)) {
|
||||
numShaderEngines = 2;
|
||||
}
|
||||
|
||||
uint infoCount = NUM_R800_CS_INFOS;
|
||||
SC_R800CSHWSHADER* cShader = (SC_R800CSHWSHADER *)shader;
|
||||
if (cShader->u32NumThreadPerGroup == 0) {
|
||||
return false;
|
||||
}
|
||||
newInfos = new CALProgramInfoEntry[infoCount];
|
||||
encoding.progInfos = newInfos;
|
||||
if (encoding.progInfos == 0) {
|
||||
infoCount = 0;
|
||||
return false;
|
||||
}
|
||||
memset(newInfos, 0, infoCount * sizeof(CALProgramInfoEntry));
|
||||
|
||||
newInfos[i].address = mmSQ_PGM_START_LS;
|
||||
newInfos[i].value = 0x0;
|
||||
i++;
|
||||
newInfos[i].address = mmSQ_PGM_RESOURCES_LS;
|
||||
cShader->sqPgmResourcesCs.bits.UNCACHED_FIRST_INST = 1;
|
||||
cShader->sqPgmResourcesCs.bits.PRIME_CACHE_ENABLE = 1;
|
||||
cShader->sqPgmResourcesCs.bits.PRIME_CACHE_ON_CONST = 0;
|
||||
newInfos[i].value = cShader->sqPgmResourcesCs.u32All;
|
||||
i++;
|
||||
newInfos[i].address = mmSQ_PGM_RESOURCES_2_LS;
|
||||
newInfos[i].value = cShader->sqPgmResources2Cs.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSPI_THREAD_GROUPING;
|
||||
regSPI_THREAD_GROUPING spi_thread_grouping;
|
||||
spi_thread_grouping.u32All = 0;
|
||||
spi_thread_grouping.bits.PS_GROUPING = 0;
|
||||
spi_thread_grouping.bits.VS_GROUPING = 0;
|
||||
spi_thread_grouping.bits.ES_GROUPING = 0;
|
||||
spi_thread_grouping.bits.GS_GROUPING = 0;
|
||||
// dyn_gpr_mgmt if CS_GROUPING = 1.
|
||||
spi_thread_grouping.bits.CS_GROUPING = 0;
|
||||
newInfos[i].value = spi_thread_grouping.u32All;
|
||||
i++;
|
||||
|
||||
const unsigned int numSharedGPR = cShader->u32NumSharedGprTotal;
|
||||
newInfos[i].address = mmSQ_DYN_GPR_CNTL_PS_FLUSH_REQ;
|
||||
regSQ_DYN_GPR_CNTL_PS_FLUSH_REQ sq_dyn_gpr_cntl_ps_flush_req;
|
||||
sq_dyn_gpr_cntl_ps_flush_req.u32All = 0;
|
||||
sq_dyn_gpr_cntl_ps_flush_req.bits.RING0_OFFSET = numSharedGPR;
|
||||
newInfos[i].value = sq_dyn_gpr_cntl_ps_flush_req.u32All;
|
||||
i++;
|
||||
|
||||
const unsigned int numClauseTemps = options.numClauseTemps_;
|
||||
const unsigned int MaxNumGPRsAvail = options.numGPRs_;
|
||||
newInfos[i].address = mmSQ_GPR_RESOURCE_MGMT_1;
|
||||
regSQ_GPR_RESOURCE_MGMT_1 sq_gpr_resource_mgmt_1;
|
||||
sq_gpr_resource_mgmt_1.u32All = 0;
|
||||
sq_gpr_resource_mgmt_1.bits.NUM_CLAUSE_TEMP_GPRS = numClauseTemps;
|
||||
newInfos[i].value = sq_gpr_resource_mgmt_1.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSQ_GPR_RESOURCE_MGMT_3__EG;
|
||||
regSQ_GPR_RESOURCE_MGMT_3__EG sq_gpr_resource_mgmt_3;
|
||||
sq_gpr_resource_mgmt_3.u32All = 0;
|
||||
{
|
||||
const unsigned int numWavefrontPerSIMD = 1 ; // ?? cShader->u32NumWavefrontPerSIMD;
|
||||
if ((cShader->u32NumSharedGprUser != cShader->u32NumSharedGprTotal)) // cShader->bIsMaxNumWavePerSIMD)
|
||||
{
|
||||
// if running with a barrier, need to limit the number of wavefronts on a SIMD.
|
||||
// force max wavefronts run on a simd by adjusting the num_es_gprs pool that all es programs can
|
||||
// allocate from. (# of gprs the program uses * numWavefrontsPerSIMD)
|
||||
sq_gpr_resource_mgmt_3.bits.NUM_LS_GPRS = cShader->sqPgmResourcesCs.bits.NUM_GPRS * numWavefrontPerSIMD;
|
||||
}
|
||||
else
|
||||
{
|
||||
sq_gpr_resource_mgmt_3.bits.NUM_LS_GPRS = MaxNumGPRsAvail - numSharedGPR;
|
||||
}
|
||||
}
|
||||
newInfos[i].value = sq_gpr_resource_mgmt_3.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSPI_GPR_MGMT;
|
||||
regSPI_GPR_MGMT spi_gpr_mgmt;
|
||||
spi_gpr_mgmt.u32All = 0;
|
||||
{
|
||||
const unsigned int numWavefrontPerSIMD = 1 ; // ?? cShader->u32NumWavefrontPerSIMD;
|
||||
if ((cShader->u32NumSharedGprUser != cShader->u32NumSharedGprTotal)) // cShader->bIsMaxNumWavePerSIMD)
|
||||
{
|
||||
// if running with a barrier, need to limit the number of wavefronts on a SIMD.
|
||||
// force max wavefronts run on a simd by adjusting the num_es_gprs pool that all es programs can
|
||||
// allocate from. (# of gprs the program uses * numWavefrontsPerSIMD)
|
||||
spi_gpr_mgmt.bits.NUM_LS_GPRS = (cShader->sqPgmResourcesCs.bits.NUM_GPRS * numWavefrontPerSIMD) >> 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_gpr_mgmt.bits.NUM_LS_GPRS = (MaxNumGPRsAvail - numSharedGPR) >> 3;
|
||||
}
|
||||
}
|
||||
newInfos[i].value = spi_gpr_mgmt.u32All;
|
||||
i++;
|
||||
|
||||
|
||||
newInfos[i].address = mmSPI_WAVE_MGMT_1;
|
||||
regSPI_WAVE_MGMT_1 spi_wave_mgmt_1;
|
||||
spi_wave_mgmt_1.u32All = 0;
|
||||
newInfos[i].value = spi_wave_mgmt_1.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSPI_WAVE_MGMT_2;
|
||||
regSPI_WAVE_MGMT_2 spi_wave_mgmt_2;
|
||||
spi_wave_mgmt_2.u32All = 0;
|
||||
spi_wave_mgmt_2.bits.NUM_CS_WAVES_ONE_RING = (options.numThreads_) >> 3;
|
||||
newInfos[i].value = spi_wave_mgmt_2.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSQ_THREAD_RESOURCE_MGMT__EG;
|
||||
regSQ_THREAD_RESOURCE_MGMT__EG sq_thread_resource_mgmt;
|
||||
sq_thread_resource_mgmt.u32All = 0;
|
||||
sq_thread_resource_mgmt.bits.NUM_PS_THREADS = 0;
|
||||
sq_thread_resource_mgmt.bits.NUM_VS_THREADS = 0;
|
||||
sq_thread_resource_mgmt.bits.NUM_GS_THREADS = 0;
|
||||
sq_thread_resource_mgmt.bits.NUM_ES_THREADS = 0;
|
||||
newInfos[i].value = sq_thread_resource_mgmt.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSQ_THREAD_RESOURCE_MGMT_2__EG;
|
||||
regSQ_THREAD_RESOURCE_MGMT_2__EG sq_thread_resource_mgmt_2;
|
||||
sq_thread_resource_mgmt_2.u32All = 0;
|
||||
sq_thread_resource_mgmt_2.bits.NUM_HS_THREADS = 0;
|
||||
sq_thread_resource_mgmt_2.bits.NUM_LS_THREADS = options.numThreads_;
|
||||
newInfos[i].value = sq_thread_resource_mgmt_2.u32All;
|
||||
i++;
|
||||
|
||||
regSPI_COMPUTE_INPUT_CNTL spi_dompute_input_cntl;
|
||||
spi_dompute_input_cntl.u32All = 0;
|
||||
spi_dompute_input_cntl.bits.DISABLE_INDEX_PACK = 1;
|
||||
spi_dompute_input_cntl.bits.TID_IN_GROUP_ENA = 1;
|
||||
spi_dompute_input_cntl.bits.TGID_ENA = 1;
|
||||
newInfos[i].address = mmSPI_COMPUTE_INPUT_CNTL;
|
||||
newInfos[i].value = spi_dompute_input_cntl.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmSQ_LDS_ALLOC;
|
||||
newInfos[i].value = cShader->sqLdsAllocCs.u32All;
|
||||
i++;
|
||||
|
||||
//This is information passed from SC to GSL, there is no valid address, so make up one.
|
||||
newInfos[i].address = AMU_ABI_CS_MAX_SCRATCH_REGS;
|
||||
newInfos[i].value = cShader->MaxScratchRegsNeeded;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_CS_NUM_SHARED_GPR_USER;
|
||||
newInfos[i].value = cShader->u32NumSharedGprUser;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_CS_NUM_SHARED_GPR_TOTAL;
|
||||
newInfos[i].value = cShader->u32NumSharedGprTotal;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP;
|
||||
newInfos[i].value = cShader->u32NumThreadPerGroup;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_X;
|
||||
newInfos[i].value = cShader->u32NumThreadPerGroup_x;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_Y;
|
||||
newInfos[i].value = cShader->u32NumThreadPerGroup_y;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_Z;
|
||||
newInfos[i].value = cShader->u32NumThreadPerGroup_z;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_TOTAL_NUM_THREAD_GROUP;
|
||||
newInfos[i].value = cShader->u32TotalNumThreadGroup;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_WAVEFRONT_PER_SIMD;
|
||||
newInfos[i].value = 1;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_IS_MAX_NUM_WAVE_PER_SIMD;
|
||||
newInfos[i].value = 0; // ??
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_SET_BUFFER_FOR_NUM_GROUP;
|
||||
newInfos[i].value = cShader->bSetBufferForNumGroup;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_RAT_OP_IS_USED;
|
||||
newInfos[i].value = cShader->u32RatOpIsUsed;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_RAT_ATOMIC_OP_IS_USED;
|
||||
newInfos[i].value = cShader->u32RatAtomicOpIsUsed;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_WAVEFRONT_SIZE;
|
||||
newInfos[i].value = nullDev().hwInfo()->simdWidth_ * 4;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_GPR_AVAIL;
|
||||
newInfos[i].value = options.numGPRs_;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_GPR_USED;
|
||||
newInfos[i].value = cShader->sqPgmResourcesCs.bits.NUM_GPRS;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_LDS_SIZE_AVAIL;
|
||||
newInfos[i].value = options.ldsSize_;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_LDS_SIZE_USED;
|
||||
newInfos[i].value = cShader->sqLdsAllocCs.bits.SIZE;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_STACK_SIZE_AVAIL;
|
||||
newInfos[i].value = options.numStackEntries_;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_STACK_SIZE_USED;
|
||||
newInfos[i].value = cShader->sqPgmResourcesCs.bits.STACK_SIZE;
|
||||
i++;
|
||||
|
||||
for (unsigned int j = 0;j <SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
unsigned int bufferSize = cShader->scUavRtnBufInfoTbl[j].stride;
|
||||
|
||||
bufferSize *= 4; // convert from DWORDS to bytes
|
||||
|
||||
//
|
||||
// multiply by the maximum number of threads in flight at one time
|
||||
//
|
||||
// 256 waves * 64 threads/wave * 2 shader engines (for 870)
|
||||
//
|
||||
bufferSize *= nullDev().hwInfo()->simdWidth_ * 4; // threads/wave
|
||||
bufferSize *= 256 * 4; // maximum number of waves
|
||||
|
||||
bufferSize *= numShaderEngines;
|
||||
|
||||
newInfos[i].address = AMU_ABI_SET_BUFFER_FOR_UAV_RET_BUFFER0 + j;
|
||||
newInfos[i].value = bufferSize;
|
||||
i++;
|
||||
}
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_BUFFER;
|
||||
newInfos[i].value = true;
|
||||
i++;
|
||||
// Always use extended caching with global return buffer
|
||||
newInfos[i].address = AMU_ABI_EXTENDED_CACHING;
|
||||
newInfos[i].value = true;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_GLOBAL_UAV;
|
||||
newInfos[i].value = SC_R800_MAX_UAV;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_GLOBAL_RETURN_BUFFER;
|
||||
newInfos[i].value = R800_GLOBAL_RTN_BUF_LAST;
|
||||
i++;
|
||||
{
|
||||
unsigned int bufferSize = cShader->u32GlobalRtnBufSlot;
|
||||
|
||||
bufferSize *= 4; // convert from DWORDS to bytes
|
||||
|
||||
//
|
||||
// multiply by the maximum number of threads in flight at one time
|
||||
//
|
||||
// 256 waves * 64 threads/wave * 2 shader engines (for 870)
|
||||
//
|
||||
bufferSize *= nullDev().hwInfo()->simdWidth_ * 4; // threads/wave
|
||||
bufferSize *= 256 * 4; // maximum number of waves
|
||||
|
||||
bufferSize *= numShaderEngines;
|
||||
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_BUFFER_SIZE;
|
||||
newInfos[i].value = bufferSize;
|
||||
i++;
|
||||
}
|
||||
{
|
||||
unsigned int bufferSize = cShader->u32GlobalRtnBufSlotShort;
|
||||
|
||||
bufferSize *= 4; // convert from DWORDS to bytes
|
||||
|
||||
//
|
||||
// multiply by the maximum number of threads in flight at one time
|
||||
//
|
||||
// 256 waves * 64 threads/wave * 2 shader engines (for 870)
|
||||
//
|
||||
bufferSize *= nullDev().hwInfo()->simdWidth_ * 4; // threads/wave
|
||||
bufferSize *= 256 * 4; // maximum number of waves
|
||||
|
||||
bufferSize *= numShaderEngines;
|
||||
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_BUFFER_SIZE_SHORT;
|
||||
newInfos[i].value = bufferSize;
|
||||
i++;
|
||||
}
|
||||
{
|
||||
unsigned int bufferSize = cShader->u32GlobalRtnBufSlotByte;
|
||||
|
||||
bufferSize *= 4; // convert from DWORDS to bytes
|
||||
|
||||
//
|
||||
// multiply by the maximum number of threads in flight at one time
|
||||
//
|
||||
// 256 waves * 64 threads/wave * 2 shader engines (for 870)
|
||||
//
|
||||
bufferSize *= nullDev().hwInfo()->simdWidth_ * 4; // threads/wave
|
||||
bufferSize *= 256 * 4; // maximum number of waves
|
||||
|
||||
bufferSize *= numShaderEngines;
|
||||
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_BUFFER_SIZE_BYTE;
|
||||
newInfos[i].value = bufferSize;
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_OFFSET_TO_UAV0+j;
|
||||
newInfos[i].value = j;
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
// Set up UAV->fetch constant mapping for uncached
|
||||
newInfos[i].address = AMU_ABI_UNCACHED_FETCH_CONST_UAV0+j;
|
||||
newInfos[i].value = UncachedFetchConst[j];
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_CACHED_FETCH_CONST_UAV0+j;
|
||||
newInfos[i].value = CachedFetchConst[j];
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < R800_GLOBAL_RTN_BUF_LAST; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_FETCH_CONST0+j;
|
||||
newInfos[i].value = GlobalReturnFetchConst[j];
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < R800_GLOBAL_RTN_BUF_LAST; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_GLOBAL_RETURN_BUFFER_TYPE0+j;
|
||||
newInfos[i].value = GlobalReturnBufferType[j];
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_CACHED_FETCH_CONST64_UAV0+j;
|
||||
newInfos[i].value = CachedFetchConst64[j];
|
||||
i++;
|
||||
}
|
||||
for (unsigned int j = 0; j < SC_R800_MAX_UAV; j++)
|
||||
{
|
||||
newInfos[i].address = AMU_ABI_CACHED_FETCH_CONST128_UAV0+j;
|
||||
newInfos[i].value = CachedFetchConst128[j];
|
||||
i++;
|
||||
}
|
||||
|
||||
assert(i == infoCount);
|
||||
encoding.progInfosCount = infoCount;
|
||||
|
||||
encoding.uavMask.mask[0] = cShader->u32RatOpIsUsed;
|
||||
encoding.textData = HWSHADER_Get(cShader, hShaderMemHandle);
|
||||
encoding.textSize = cShader->CodeLenInByte;
|
||||
instructionCnt_ = encoding.textSize / sizeof(uint32_t);
|
||||
encoding.scratchRegisterCount = cShader->MaxScratchRegsNeeded;
|
||||
|
||||
uint bufferSize = 0;
|
||||
bufferSize = cShader->u32GlobalRtnBufSlot +
|
||||
cShader->u32GlobalRtnBufSlotShort + cShader->u32GlobalRtnBufSlotByte;
|
||||
bufferSize *= 4; // convert from DWORDS to bytes
|
||||
|
||||
//
|
||||
// multiply by the maximum number of threads in flight at one time
|
||||
//
|
||||
// 256 waves * 64 threads/wave * 2 shader engines (for 870)
|
||||
//
|
||||
bufferSize *= nullDev().hwInfo()->simdWidth_ * 4; // threads/wave
|
||||
bufferSize *= 256 * 4; // maximum number of waves
|
||||
|
||||
bufferSize *= numShaderEngines;
|
||||
encoding.UAVReturnBufferTotalSize = bufferSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpuprogram.hpp"
|
||||
#include "device/gpu/gpukernel.hpp"
|
||||
#include "acl.h"
|
||||
#include "SCShadersSi.h"
|
||||
#include "si_ci_merged_offset.h"
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
bool
|
||||
NullKernel::siCreateHwInfo(const void* shader, AMUabiAddEncoding& encoding)
|
||||
{
|
||||
static const uint NumSiCsInfos = (70 + 5 + 1 + 32 + 6);
|
||||
CALProgramInfoEntry* newInfos;
|
||||
uint i = 0;
|
||||
uint infoCount = NumSiCsInfos;
|
||||
const SC_SI_HWSHADER_CS* cShader = reinterpret_cast<const SC_SI_HWSHADER_CS*>(shader);
|
||||
newInfos = new CALProgramInfoEntry[infoCount];
|
||||
encoding.progInfos = newInfos;
|
||||
if (encoding.progInfos == 0) {
|
||||
infoCount = 0;
|
||||
return false;
|
||||
}
|
||||
newInfos[i].address = AMU_ABI_USER_ELEMENT_COUNT;
|
||||
newInfos[i].value = cShader->common.userElementCount;
|
||||
i++;
|
||||
for (unsigned int j = 0; j < cShader->common.userElementCount; j++) {
|
||||
newInfos[i].address = AMU_ABI_USER_ELEMENTS_0_DWORD0 + 4*j;
|
||||
newInfos[i].value = HWSHADER_Get(cShader, common.pUserElements)[j].dataClass;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_USER_ELEMENTS_0_DWORD1 + 4*j;
|
||||
newInfos[i].value = HWSHADER_Get(cShader, common.pUserElements)[j].apiSlot;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_USER_ELEMENTS_0_DWORD2 + 4*j;
|
||||
newInfos[i].value = HWSHADER_Get(cShader, common.pUserElements)[j].startUserReg;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_USER_ELEMENTS_0_DWORD3 + 4*j;
|
||||
newInfos[i].value = HWSHADER_Get(cShader, common.pUserElements)[j].userRegCount;
|
||||
i++;
|
||||
}
|
||||
|
||||
newInfos[i].address = AMU_ABI_SI_NUM_VGPRS;
|
||||
newInfos[i].value = cShader->common.numVgprs;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_SI_NUM_SGPRS;
|
||||
newInfos[i].value = cShader->common.numSgprs;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_SI_NUM_SGPRS_AVAIL;
|
||||
newInfos[i].value = 104-2; //512;//options.NumSGPRsAvailable;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_SI_NUM_VGPRS_AVAIL;
|
||||
newInfos[i].value = 256;//options.NumVGPRsAvailable;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_SI_FLOAT_MODE;
|
||||
newInfos[i].value = cShader->common.floatMode;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_SI_IEEE_MODE;
|
||||
newInfos[i].value = cShader->common.bIeeeMode;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_SI_SCRATCH_SIZE;
|
||||
newInfos[i].value = cShader->common.scratchSize;;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = mmCOMPUTE_PGM_RSRC2;
|
||||
newInfos[i].value = cShader->computePgmRsrc2.u32All;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_X;
|
||||
newInfos[i].value = cShader->numThreadX;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_Y;
|
||||
newInfos[i].value = cShader->numThreadY;
|
||||
i++;
|
||||
newInfos[i].address = AMU_ABI_NUM_THREAD_PER_GROUP_Z;
|
||||
newInfos[i].value = cShader->numThreadZ;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_ORDERED_APPEND_ENABLE;
|
||||
newInfos[i].value = cShader->bOrderedAppendEnable;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_RAT_OP_IS_USED;
|
||||
newInfos[i].value = cShader->common.uavResourceUsage[0];
|
||||
i++;
|
||||
|
||||
for (unsigned int j = 0; j < ((SC_MAX_UAV + 31) / 32); j++) {
|
||||
newInfos[i].address = AMU_ABI_UAV_RESOURCE_MASK_0 + j;
|
||||
newInfos[i].value = cShader->common.uavResourceUsage[j];
|
||||
i++;
|
||||
}
|
||||
|
||||
newInfos[i].address = AMU_ABI_NUM_WAVEFRONT_PER_SIMD; // Setting the same as for scWrapR800Info
|
||||
newInfos[i].value = 1;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_WAVEFRONT_SIZE;
|
||||
newInfos[i].value = nullDev().hwInfo()->simdWidth_ * 4; //options.WavefrontSize;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_LDS_SIZE_AVAIL;
|
||||
newInfos[i].value = 32*1024; //options.LDSSize;
|
||||
i++;
|
||||
|
||||
newInfos[i].address = AMU_ABI_LDS_SIZE_USED;
|
||||
newInfos[i].value = 64 * 4 * cShader->computePgmRsrc2.bits.LDS_SIZE;
|
||||
i++;
|
||||
|
||||
infoCount = i;
|
||||
assert((i + 4 * (16 - cShader->common.userElementCount)) == NumSiCsInfos);
|
||||
encoding.progInfosCount = infoCount;
|
||||
|
||||
CALUavMask uavMask;
|
||||
memcpy(uavMask.mask, cShader->common.uavResourceUsage, sizeof(CALUavMask));
|
||||
encoding.uavMask = uavMask;
|
||||
encoding.textData = HWSHADER_Get(cShader, common.hShaderMemHandle);
|
||||
encoding.textSize = cShader->common.codeLenInByte;
|
||||
instructionCnt_ = encoding.textSize / sizeof(uint32_t);
|
||||
encoding.scratchRegisterCount = cShader->common.scratchSize;
|
||||
encoding.UAVReturnBufferTotalSize = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
HSAILKernel::aqlCreateHWInfo(const void* shader, size_t shaderSize)
|
||||
{
|
||||
// Copy the shader_isa into a buffer
|
||||
hwMetaData_ = new char[shaderSize];
|
||||
if (hwMetaData_ == NULL) {
|
||||
return false;
|
||||
}
|
||||
memcpy(hwMetaData_, shader, shaderSize);
|
||||
|
||||
SC_SI_HWSHADER_CS* siMetaData = reinterpret_cast<SC_SI_HWSHADER_CS*>(hwMetaData_);
|
||||
|
||||
// Code to patch the pointers in the shader object.
|
||||
// Must be preferably done in the compiler library
|
||||
size_t offset = siMetaData->common.uSizeInBytes;
|
||||
if (siMetaData->common.u32PvtDataSizeInBytes > 0) {
|
||||
siMetaData->common.pPvtData =
|
||||
reinterpret_cast<SC_BYTE *>(
|
||||
reinterpret_cast<char *>(siMetaData) + offset);
|
||||
offset += siMetaData->common.u32PvtDataSizeInBytes;
|
||||
}
|
||||
if (siMetaData->common.codeLenInByte > 0) {
|
||||
siMetaData->common.hShaderMemHandle =
|
||||
reinterpret_cast<char *>(siMetaData) + offset;
|
||||
offset += siMetaData->common.codeLenInByte;
|
||||
}
|
||||
|
||||
char* headerBaseAddress =
|
||||
reinterpret_cast<char*>(siMetaData->common.hShaderMemHandle);
|
||||
hsa_ext_code_descriptor_t* hcd =
|
||||
reinterpret_cast<hsa_ext_code_descriptor_t*>(headerBaseAddress);
|
||||
amd_kernel_code_t* akc = reinterpret_cast<amd_kernel_code_t*>(
|
||||
headerBaseAddress + hcd->code.handle);
|
||||
|
||||
address codeStartAddress = reinterpret_cast<address>(akc);
|
||||
address codeEndAddress = reinterpret_cast<address>(hcd) + siMetaData->common.codeLenInByte;
|
||||
uint64_t codeSize = codeEndAddress - codeStartAddress;
|
||||
code_ = new gpu::Memory(dev(), amd::alignUp(codeSize, gpu::ConstBuffer::VectorSize));
|
||||
// Initialize kernel ISA code
|
||||
if ((code_ != NULL) && code_->create(Resource::Local)) {
|
||||
address cpuCodePtr = static_cast<address>(code_->map(NULL, Resource::WriteOnly));
|
||||
// Copy only amd_kernel_code_t
|
||||
memcpy(cpuCodePtr, codeStartAddress, codeSize);
|
||||
code_->unmap(NULL);
|
||||
}
|
||||
else {
|
||||
LogError("Failed to allocate ISA code!");
|
||||
return false;
|
||||
}
|
||||
cpuAqlCode_ = akc;
|
||||
|
||||
assert((akc->workitem_private_segment_byte_size & 3) == 0 &&
|
||||
"Scratch must be DWORD aligned");
|
||||
workGroupInfo_.scratchRegs_ =
|
||||
akc->workitem_private_segment_byte_size / sizeof(uint);
|
||||
workGroupInfo_.availableSGPRs_ = dev().gslCtx()->getNumSGPRsAvailable();
|
||||
workGroupInfo_.availableVGPRs_ = dev().gslCtx()->getNumVGPRsAvailable();
|
||||
workGroupInfo_.preferredSizeMultiple_ = dev().getAttribs().wavefrontSize;
|
||||
workGroupInfo_.privateMemSize_ = akc->workitem_private_segment_byte_size;
|
||||
workGroupInfo_.localMemSize_ =
|
||||
workGroupInfo_.usedLDSSize_ = akc->workgroup_group_segment_byte_size;
|
||||
workGroupInfo_.usedSGPRs_ = akc->wavefront_sgpr_count;
|
||||
workGroupInfo_.usedStackSize_ = 0;
|
||||
workGroupInfo_.usedVGPRs_ = akc->workitem_vgpr_count;
|
||||
workGroupInfo_.wavefrontPerSIMD_ = dev().getAttribs().wavefrontSize;
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,483 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "top.hpp"
|
||||
#include "os/os.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpusettings.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace gpu {
|
||||
|
||||
Settings::Settings()
|
||||
{
|
||||
// Initialize the GPU device default settings
|
||||
oclVersion_ = OpenCL12;
|
||||
debugFlags_ = 0;
|
||||
singleHeap_ = false;
|
||||
syncObject_ = GPU_USE_SYNC_OBJECTS;
|
||||
remoteAlloc_ = REMOTE_ALLOC;
|
||||
|
||||
stagedXferRead_ = true;
|
||||
stagedXferWrite_ = true;
|
||||
stagedXferSize_ = GPU_STAGING_BUFFER_SIZE * Ki;
|
||||
|
||||
// We will enable staged read/write if we use local memory
|
||||
disablePersistent_ = false;
|
||||
|
||||
// By Default persistent writes will be disabled.
|
||||
stagingWritePersistent_ = GPU_STAGING_WRITE_PERSISTENT;
|
||||
|
||||
maxRenames_ = 32;
|
||||
maxRenameSize_ = 4 * Mi;
|
||||
|
||||
// The global heap settings
|
||||
heapSize_ = GPU_INITIAL_HEAP_SIZE * Mi;
|
||||
heapSizeGrowth_ = GPU_HEAP_GROWTH_INCREMENT * Mi;
|
||||
|
||||
useAliases_ = false;
|
||||
imageSupport_ = false;
|
||||
hwLDSSize_ = 0;
|
||||
|
||||
// Set this to true when we drop the flag
|
||||
doublePrecision_ = ::CL_KHR_FP64;
|
||||
|
||||
// Fill workgroup info size
|
||||
// @todo: revisit the 256 limitation on workgroup size
|
||||
maxWorkGroupSize_ = 256;
|
||||
|
||||
hostMemDirectAccess_ = HostMemDisable;
|
||||
|
||||
libSelector_ = amd::LibraryUndefined;
|
||||
|
||||
#if cl_amd_open_video
|
||||
// By default Open Video extension is not yet supported
|
||||
openVideo_ = false;
|
||||
#endif // cl_amd_open_video
|
||||
|
||||
// Enable workload split by default (for 24 bit arithmetic or timeout)
|
||||
workloadSplitSize_ = 1 << GPU_WORKLOAD_SPLIT;
|
||||
|
||||
// By default use host blit
|
||||
blitEngine_ = BlitEngineHost;
|
||||
const static size_t MaxPinnedXferSize = 32;
|
||||
pinnedXferSize_ = std::min(GPU_PINNED_XFER_SIZE, MaxPinnedXferSize) * Mi;
|
||||
pinnedMinXferSize_ = std::min(GPU_PINNED_MIN_XFER_SIZE * Ki, pinnedXferSize_);
|
||||
|
||||
// Disable FP_FAST_FMA defines by default
|
||||
reportFMAF_ = false;
|
||||
reportFMA_ = false;
|
||||
|
||||
// Disable async memory transfers by default
|
||||
asyncMemCopy_ = false;
|
||||
|
||||
// GPU device by default
|
||||
apuSystem_ = false;
|
||||
|
||||
// Save resource cache size
|
||||
resourceCacheSize_ = GPU_RESOURCE_CACHE_SIZE * Mi;
|
||||
|
||||
// Disable 64 bit pointers support by default
|
||||
use64BitPtr_ = false;
|
||||
|
||||
// Max alloc size is 16GB
|
||||
maxAllocSize_ = 16 * static_cast<uint64_t>(Gi);
|
||||
|
||||
// Disable memory dependency tracking by default
|
||||
numMemDependencies_ = 0;
|
||||
|
||||
// By default cache isn't present
|
||||
cacheLineSize_ = 0;
|
||||
cacheSize_ = 0;
|
||||
|
||||
// Initialize transfer buffer size to 1MB by default
|
||||
xferBufSize_ = 1024 * Ki;
|
||||
|
||||
// Use image DMA if requested
|
||||
imageDMA_ = GPU_IMAGE_DMA;
|
||||
|
||||
// Disable ASIC specific features by default
|
||||
siPlus_ = false;
|
||||
ciPlus_ = false;
|
||||
viPlus_ = false;
|
||||
|
||||
// Number of compute rings.
|
||||
numComputeRings_ = 0;
|
||||
|
||||
// Rectangular Linear DRMDMA
|
||||
rectLinearDMA_ = false;
|
||||
|
||||
minWorkloadTime_ = 1; // 0.1 ms
|
||||
maxWorkloadTime_ = 5000; // 500 ms
|
||||
|
||||
// Preallocates address space
|
||||
preallocAddrSpace_ = GPU_PREALLOC_ADDR_SPACE;
|
||||
|
||||
// Controls tiled images in persistent
|
||||
//!@note IOL for Linux doesn't setup tiling aperture in CMM/QS
|
||||
linearPersistentImage_ = false;
|
||||
|
||||
useSingleScratch_ = GPU_USE_SINGLE_SCRATCH;
|
||||
|
||||
// SDMA profiling is disabled by default
|
||||
sdmaProfiling_ = false;
|
||||
|
||||
// Device enqueuing settings
|
||||
numDeviceEvents_ = 1024;
|
||||
numWaitEvents_ = 8;
|
||||
|
||||
// Disable HSAIL by default
|
||||
hsail_ = false;
|
||||
|
||||
// Don't support platform atomics by default.
|
||||
svmAtomics_ = false;
|
||||
|
||||
// Use direct SRD by default
|
||||
hsailDirectSRD_ = GPU_DIRECT_SRD;
|
||||
}
|
||||
|
||||
bool
|
||||
Settings::create(
|
||||
const CALdeviceattribs& calAttr
|
||||
#if cl_amd_open_video
|
||||
, const CALdeviceVideoAttribs& calVideoAttr
|
||||
#endif // cl_amd_open_video
|
||||
, bool reportAsOCL12Device
|
||||
)
|
||||
{
|
||||
CALuint target = calAttr.target;
|
||||
uint32_t osVer = 0x0;
|
||||
|
||||
// Disable thread trace by default for all devices
|
||||
threadTraceEnable_ = false;
|
||||
|
||||
if (calAttr.doublePrecision) {
|
||||
// Report FP_FAST_FMA define if double precision HW
|
||||
reportFMA_ = true;
|
||||
// FMA is 1/4 speed on Pitcairn, Cape Verde, Devastator and Scrapper
|
||||
// Bonaire, Kalindi, Spectre and Spooky so disable
|
||||
// FP_FMA_FMAF for those parts in switch below
|
||||
reportFMAF_ = true;
|
||||
}
|
||||
|
||||
// Update GPU specific settings and info structure if we have any
|
||||
switch (target) {
|
||||
case CAL_TARGET_SUMO:
|
||||
case CAL_TARGET_SUPERSUMO:
|
||||
case CAL_TARGET_WRESTLER:
|
||||
// Treat these like Evergreen parts as far as capabilities go
|
||||
// Fall through ...
|
||||
case CAL_TARGET_DEVASTATOR:
|
||||
case CAL_TARGET_SCRAPPER:
|
||||
apuSystem_ = true;
|
||||
reportFMAF_ = false;
|
||||
// For the system that has APU and Win 8, the work load needs to be smaller
|
||||
// This is because KMD doesn't have workaround for TDR in Win 8
|
||||
// This is needed only for EG/NI because EG/NI is using graphics ring
|
||||
#if defined(_WIN32)
|
||||
{
|
||||
OSVERSIONINFOEX versionInfo = { 0 };
|
||||
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
versionInfo.dwMajorVersion = 6;
|
||||
versionInfo.dwMinorVersion = 2;
|
||||
|
||||
DWORDLONG conditionMask = 0;
|
||||
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
if (VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask)) {
|
||||
maxWorkloadTime_ = 500; // 50 ms
|
||||
}
|
||||
}
|
||||
#endif // defined(_WIN32)
|
||||
// Add the caps for Trinity here ...
|
||||
// Fall through ...
|
||||
case CAL_TARGET_CAYMAN:
|
||||
// Add the caps for Cayman here ...
|
||||
case CAL_TARGET_KAUAI:
|
||||
case CAL_TARGET_BARTS:
|
||||
case CAL_TARGET_TURKS:
|
||||
case CAL_TARGET_CAICOS:
|
||||
// Treat these like Evergreen parts as far as capabilities go
|
||||
// Fall through ...
|
||||
case CAL_TARGET_CYPRESS:
|
||||
case CAL_TARGET_JUNIPER:
|
||||
case CAL_TARGET_REDWOOD:
|
||||
case CAL_TARGET_CEDAR:
|
||||
// UAV arena is a pre-SI specific HW feature
|
||||
useAliases_ = true;
|
||||
|
||||
if (CAL_TARGET_CEDAR == target) {
|
||||
// Workaround for SC spill bugs.
|
||||
maxWorkGroupSize_ = 128;
|
||||
}
|
||||
// Get the link library
|
||||
libSelector_ = amd::GPU_Library_Evergreen;
|
||||
|
||||
// Max alloc size
|
||||
maxAllocSize_ = 512 * Mi;
|
||||
|
||||
if ((target == CAL_TARGET_CAYMAN) ||
|
||||
(target == CAL_TARGET_DEVASTATOR) ||
|
||||
(target == CAL_TARGET_SCRAPPER)) {
|
||||
rectLinearDMA_ = true;
|
||||
}
|
||||
|
||||
// Disable KHR_FP64 for Trinity in the mainline
|
||||
if ((target == CAL_TARGET_DEVASTATOR) ||
|
||||
(target == CAL_TARGET_SCRAPPER)) {
|
||||
doublePrecision_ &= !IS_MAINLINE || !flagIsDefault(CL_KHR_FP64);
|
||||
}
|
||||
|
||||
if (target == CAL_TARGET_CYPRESS) {
|
||||
// Float FMA is slower than "multiply + add" because we combine
|
||||
// "multiply + add" into mad. MAD is 25% faster than FMA on Cypress,
|
||||
// assuming perfect VLIW packing.
|
||||
reportFMAF_ = false;
|
||||
}
|
||||
enableExtension(ClAmdImage2dFromBufferReadOnly);
|
||||
break;
|
||||
case CAL_TARGET_ICELAND:
|
||||
case CAL_TARGET_TONGA:
|
||||
case CAL_TARGET_BERMUDA:
|
||||
case CAL_TARGET_FIJI:
|
||||
case CAL_TARGET_CARRIZO:
|
||||
// Disable tiling aperture on VI+
|
||||
linearPersistentImage_ = true;
|
||||
viPlus_ = true;
|
||||
// Fall through to CI ...
|
||||
case CAL_TARGET_KALINDI:
|
||||
case CAL_TARGET_SPECTRE:
|
||||
case CAL_TARGET_SPOOKY:
|
||||
case CAL_TARGET_GODAVARI:
|
||||
if (!viPlus_) {
|
||||
// APU systems for CI
|
||||
apuSystem_ = true;
|
||||
}
|
||||
// Fall through ...
|
||||
case CAL_TARGET_BONAIRE:
|
||||
case CAL_TARGET_HAWAII:
|
||||
ciPlus_ = true;
|
||||
sdmaProfiling_ = true;
|
||||
hsail_ = GPU_HSAIL_ENABLE;
|
||||
// Fall through to SI ...
|
||||
case CAL_TARGET_PITCAIRN:
|
||||
case CAL_TARGET_CAPEVERDE:
|
||||
case CAL_TARGET_OLAND:
|
||||
case CAL_TARGET_HAINAN:
|
||||
reportFMAF_ = false;
|
||||
if (target == CAL_TARGET_HAWAII) {
|
||||
reportFMAF_ = true;
|
||||
}
|
||||
// Fall through ...
|
||||
case CAL_TARGET_TAHITI:
|
||||
siPlus_ = true;
|
||||
// Cache line size is 64 bytes
|
||||
cacheLineSize_ = 64;
|
||||
// L1 cache size is 16KB
|
||||
cacheSize_ = 16 * Ki;
|
||||
|
||||
if (ciPlus_) {
|
||||
libSelector_ = amd::GPU_Library_CI;
|
||||
#if defined(_LP64)
|
||||
oclVersion_ = reportAsOCL12Device ? OpenCL12 : XCONCAT(OpenCL,XCONCAT(OPENCL_MAJOR,OPENCL_MINOR));
|
||||
#endif
|
||||
if (GPU_FORCE_OCL20_32BIT) {
|
||||
force32BitOcl20_ = true;
|
||||
oclVersion_ = reportAsOCL12Device ? OpenCL12 : XCONCAT(OpenCL,XCONCAT(OPENCL_MAJOR,OPENCL_MINOR));
|
||||
}
|
||||
if (hsail_) {
|
||||
oclVersion_ = OpenCL12;
|
||||
}
|
||||
numComputeRings_ = 8;
|
||||
}
|
||||
else {
|
||||
numComputeRings_ = 2;
|
||||
libSelector_ = amd::GPU_Library_SI;
|
||||
}
|
||||
|
||||
// This needs to be cleaned once 64bit addressing is stable
|
||||
if (oclVersion_ < OpenCL20) {
|
||||
use64BitPtr_ = flagIsDefault(GPU_FORCE_64BIT_PTR) ? LP64_SWITCH(false,
|
||||
calAttr.isWorkstation || hsail_) : GPU_FORCE_64BIT_PTR;
|
||||
}
|
||||
else {
|
||||
if (GPU_FORCE_64BIT_PTR || LP64_SWITCH(false, (hsail_
|
||||
|| (oclVersion_ >= OpenCL20)))) {
|
||||
use64BitPtr_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (oclVersion_ >= OpenCL20) {
|
||||
supportDepthsRGB_ = true;
|
||||
}
|
||||
if (use64BitPtr_) {
|
||||
maxAllocSize_ = 4048 * Mi;
|
||||
}
|
||||
else {
|
||||
maxAllocSize_ = 3ULL * Gi;
|
||||
}
|
||||
|
||||
supportRA_ = false;
|
||||
partialDispatch_ = GPU_PARTIAL_DISPATCH;
|
||||
numMemDependencies_ = GPU_NUM_MEM_DEPENDENCY;
|
||||
|
||||
//! @todo HSAIL doesn't support 64 bit atomic on 32 bit!
|
||||
if (LP64_SWITCH(!hsail_, true)) {
|
||||
enableExtension(ClKhrInt64BaseAtomics);
|
||||
enableExtension(ClKhrInt64ExtendedAtomics);
|
||||
}
|
||||
enableExtension(ClKhrImage2dFromBuffer);
|
||||
|
||||
rectLinearDMA_ = true;
|
||||
|
||||
if (AMD_DEPTH_MSAA_INTEROP) {
|
||||
enableExtension(ClKhrGLDepthImages);
|
||||
depthMSAAInterop_ = true;
|
||||
}
|
||||
if (AMD_THREAD_TRACE_ENABLE) {
|
||||
threadTraceEnable_ = true;
|
||||
}
|
||||
// Disable non-aliased(multiUAV) optimization
|
||||
assumeAliases_ = true;
|
||||
break;
|
||||
default:
|
||||
assert(0 && "Unknown ASIC type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable atomics support
|
||||
enableExtension(ClKhrGlobalInt32BaseAtomics);
|
||||
enableExtension(ClKhrGlobalInt32ExtendedAtomics);
|
||||
enableExtension(ClKhrLocalInt32BaseAtomics);
|
||||
enableExtension(ClKhrLocalInt32ExtendedAtomics);
|
||||
enableExtension(ClKhrByteAddressableStore);
|
||||
enableExtension(ClKhrGlSharing);
|
||||
enableExtension(ClKhrGlEvent);
|
||||
enableExtension(ClAmdMediaOps);
|
||||
enableExtension(ClAmdMediaOps2);
|
||||
enableExtension(ClAmdPopcnt);
|
||||
#if defined(_WIN32)
|
||||
enableExtension(ClKhrD3d9Sharing);
|
||||
enableExtension(ClKhrD3d10Sharing);
|
||||
enableExtension(ClKhrD3d11Sharing);
|
||||
#endif // _WIN32
|
||||
enableExtension(ClKhr3DImageWrites);
|
||||
enableExtension(ClAmdVec3);
|
||||
enableExtension(ClAmdPrintf);
|
||||
enableExtension(ClExtAtomicCounters32);
|
||||
|
||||
hwLDSSize_ = 32 * Ki;
|
||||
|
||||
imageSupport_ = true;
|
||||
singleHeap_ = true;
|
||||
customSvmAllocator_ = true;
|
||||
|
||||
// Use kernels for blit if appropriate
|
||||
blitEngine_ = BlitEngineKernel;
|
||||
|
||||
#if cl_amd_open_video
|
||||
// Enable OpenVideo by default if CAL supports it
|
||||
if (calVideoAttr.max_decode_sessions > 0) {
|
||||
openVideo_ = true;
|
||||
if (GPU_OPEN_VIDEO)
|
||||
enableExtension(ClAmdOpenVideo);
|
||||
}
|
||||
#endif // cl_amd_open_video
|
||||
|
||||
hostMemDirectAccess_ |= HostMemBuffer;
|
||||
// HW doesn't support untiled image writes
|
||||
// hostMemDirectAccess_ |= HostMemImage;
|
||||
|
||||
asyncMemCopy_ = true;
|
||||
|
||||
// Make sure device actually supports double precision
|
||||
doublePrecision_ = (calAttr.doublePrecision) ? doublePrecision_ : false;
|
||||
if (doublePrecision_) {
|
||||
// Enable KHR double precision extension
|
||||
enableExtension(ClKhrFp64);
|
||||
}
|
||||
|
||||
if (calAttr.doublePrecision) {
|
||||
// Enable AMD double precision extension
|
||||
doublePrecision_ = true;
|
||||
enableExtension(ClAmdFp64);
|
||||
}
|
||||
|
||||
if (calAttr.totalSDIHeap > 0) {
|
||||
//Enable bus addressable memory extension
|
||||
enableExtension(ClAMDBusAddressableMemory);
|
||||
}
|
||||
|
||||
if (calAttr.longIdleDetect) {
|
||||
// KMD is unable to detect if we map the visible memory for CPU access, so
|
||||
// accessing persistent staged buffer may fail if LongIdleDetct is enabled.
|
||||
disablePersistent_ = true;
|
||||
}
|
||||
|
||||
if (calAttr.priSupport) {
|
||||
svmAtomics_ = true;
|
||||
}
|
||||
|
||||
// Enable some platform extensions
|
||||
enableExtension(ClAmdDeviceAttributeQuery);
|
||||
|
||||
enableExtension(ClKhrSpir);
|
||||
|
||||
// Enable some OpenCL 2.0 extensions
|
||||
if (oclVersion_ >= OpenCL20) {
|
||||
enableExtension(ClKhrSubGroups);
|
||||
}
|
||||
|
||||
// Override current device settings
|
||||
override();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Settings::override()
|
||||
{
|
||||
// Limit reported workgroup size
|
||||
if (GPU_MAX_WORKGROUP_SIZE != 0) {
|
||||
maxWorkGroupSize_ = GPU_MAX_WORKGROUP_SIZE;
|
||||
}
|
||||
|
||||
// Override blit engine type
|
||||
if (GPU_BLIT_ENGINE_TYPE != BlitEngineDefault) {
|
||||
blitEngine_ = GPU_BLIT_ENGINE_TYPE;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(DEBUG_GPU_FLAGS)) {
|
||||
debugFlags_ = DEBUG_GPU_FLAGS;
|
||||
}
|
||||
|
||||
// Check async memory transfer
|
||||
if (!flagIsDefault(GPU_ASYNC_MEM_COPY)) {
|
||||
asyncMemCopy_ = GPU_ASYNC_MEM_COPY;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(DEBUG_GPU_FLAGS)) {
|
||||
debugFlags_ = DEBUG_GPU_FLAGS;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(GPU_XFER_BUFFER_SIZE)) {
|
||||
xferBufSize_ = GPU_XFER_BUFFER_SIZE * Ki;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(GPU_USE_SYNC_OBJECTS)) {
|
||||
syncObject_ = GPU_USE_SYNC_OBJECTS;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(GPU_NUM_COMPUTE_RINGS)) {
|
||||
numComputeRings_ = GPU_NUM_COMPUTE_RINGS;
|
||||
}
|
||||
|
||||
if (!flagIsDefault(GPU_ASSUME_ALIASES)) {
|
||||
assumeAliases_ = GPU_ASSUME_ALIASES;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUSETTINGS_HPP_
|
||||
#define GPUSETTINGS_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "library.hpp"
|
||||
|
||||
/*! \addtogroup GPU GPU Resource Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
//! Device settings
|
||||
class Settings : public device::Settings
|
||||
{
|
||||
public:
|
||||
//! Debug GPU flags
|
||||
enum DebugGpuFlags
|
||||
{
|
||||
CheckForILSource = 0x00000001,
|
||||
StubCLPrograms = 0x00000002, //!< Enables OpenCL programs stubbing
|
||||
LockGlobalMemory = 0x00000004,
|
||||
};
|
||||
|
||||
enum BlitEngineType
|
||||
{
|
||||
BlitEngineDefault = 0x00000000,
|
||||
BlitEngineHost = 0x00000001,
|
||||
BlitEngineCAL = 0x00000002,
|
||||
BlitEngineKernel = 0x00000003,
|
||||
};
|
||||
|
||||
enum HostMemFlags
|
||||
{
|
||||
HostMemDisable = 0x00000000,
|
||||
HostMemBuffer = 0x00000001,
|
||||
HostMemImage = 0x00000002,
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint singleHeap_: 1; //!< Device will use a preallocated heap
|
||||
uint remoteAlloc_: 1; //!< Allocate remote memory for the heap
|
||||
uint stagedXferRead_: 1; //!< Uses a staged buffer read
|
||||
uint stagedXferWrite_: 1; //!< Uses a staged buffer write
|
||||
uint disablePersistent_: 1; //!< Disables using persistent memory for staging
|
||||
uint useAliases_: 1; //!< Enables global heap aliases in HW
|
||||
uint imageSupport_: 1; //!< Report images support
|
||||
uint doublePrecision_: 1; //!< Enables double precision support
|
||||
uint openVideo_: 1; //!< Open Video interop support
|
||||
uint reportFMAF_: 1; //!< Report FP_FAST_FMAF define in CL program
|
||||
uint reportFMA_: 1; //!< Report FP_FAST_FMA define in CL program
|
||||
uint use64BitPtr_: 1; //!< Use 64bit pointers on GPU
|
||||
uint force32BitOcl20_: 1; //!< Force 32bit apps to take CLANG/HSAIL path on GPU
|
||||
uint imageDMA_: 1; //!< Enable direct image DMA transfers
|
||||
uint syncObject_: 1; //!< Enable syncobject
|
||||
uint siPlus_: 1; //!< SI and post SI features
|
||||
uint ciPlus_: 1; //!< CI and post CI features
|
||||
uint viPlus_: 1; //!< VI and post VI features
|
||||
uint rectLinearDMA_: 1; //!< Rectangular linear DRMDMA support
|
||||
uint threadTraceEnable_: 1; //!< Thread trace enable
|
||||
uint preallocAddrSpace_: 1; //!< Preallocates address space
|
||||
uint linearPersistentImage_: 1; //!< Allocates linear images in persistent
|
||||
uint useSingleScratch_: 1; //!< Allocates single scratch per device
|
||||
uint sdmaProfiling_: 1; //!< Enables SDMA profiling
|
||||
uint hsail_: 1; //!< Enables HSAIL compilation
|
||||
uint stagingWritePersistent_: 1; //!< Enables persistent writes
|
||||
uint svmAtomics_: 1; //!< SVM device atomics
|
||||
uint apuSystem_: 1; //!< Device is APU system with shared memory
|
||||
uint asyncMemCopy_: 1; //!< Use async memory transfers
|
||||
uint hsailDirectSRD_: 1; //!< Controls direct SRD for HSAIL
|
||||
uint reserved_: 2;
|
||||
};
|
||||
uint value_;
|
||||
};
|
||||
|
||||
uint oclVersion_; //!< Reported OpenCL version support
|
||||
uint debugFlags_; //!< Debug GPU flags
|
||||
size_t stagedXferSize_; //!< Staged buffer size
|
||||
uint maxRenames_; //!< Maximum number of possible renames
|
||||
uint maxRenameSize_; //!< Maximum size for all renames
|
||||
size_t heapSize_; //!< The global heap size
|
||||
size_t heapSizeGrowth_; //!< The global heap size growth
|
||||
uint hwLDSSize_; //!< HW local data store size
|
||||
uint maxWorkGroupSize_; //!< Requested workgroup size for this device
|
||||
uint hostMemDirectAccess_; //!< Enables direct access to the host memory
|
||||
amd::LibrarySelector libSelector_; //!< Select linking libraries for compiler
|
||||
uint workloadSplitSize_; //!< Workload split size
|
||||
uint minWorkloadTime_; //!< Minimal workload time in 0.1 ms
|
||||
uint maxWorkloadTime_; //!< Maximum workload time in 0.1 ms
|
||||
uint blitEngine_; //!< Blit engine type
|
||||
size_t pinnedXferSize_; //!< Pinned buffer size for transfer
|
||||
size_t pinnedMinXferSize_; //!< Minimal buffer size for pinned transfer
|
||||
size_t resourceCacheSize_; //!< Resource cache size in MB
|
||||
uint64_t maxAllocSize_; //!< Maximum single allocation size
|
||||
size_t numMemDependencies_;//!< The array size for memory dependencies tracking
|
||||
uint cacheLineSize_; //!< Cache line size in bytes
|
||||
uint cacheSize_; //!< L1 cache size in bytes
|
||||
size_t xferBufSize_; //!< Transfer buffer size for image copy optimization
|
||||
uint numComputeRings_; //!< 0 - disabled, 1 , 2,.. - the number of compute rings
|
||||
uint numDeviceEvents_; //!< The number of device events
|
||||
uint numWaitEvents_; //!< The number of wait events for device enqueue
|
||||
|
||||
|
||||
//! Default constructor
|
||||
Settings();
|
||||
|
||||
//! Creates settings
|
||||
bool create(
|
||||
const CALdeviceattribs& calAttr //!< CAL attributes structure
|
||||
#if cl_amd_open_video
|
||||
, const CALdeviceVideoAttribs& calVideoAttr //!< CAL video attributes
|
||||
#endif // cl_amd_open_video
|
||||
, bool reportAsOCL12Device = false //!< Report As OpenCL1.2 Device
|
||||
);
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
Settings(const Settings&);
|
||||
|
||||
//! Disable assignment
|
||||
Settings& operator=(const Settings&);
|
||||
|
||||
//! Overrides current settings based on registry/environment
|
||||
void override();
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUSETTINGS_HPP_*/
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "device/gpu/gputhreadtrace.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
CalThreadTraceReference::~CalThreadTraceReference() {
|
||||
// The thread trace object is always associated with a particular queue,
|
||||
// so we have to lock just this queue
|
||||
amd::ScopedLock lock(gpu_.execution());
|
||||
|
||||
if (0 != threadTrace_) {
|
||||
//gpu().destroyThreadTrace(gslThreadTrace());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ThreadTrace::~ThreadTrace()
|
||||
{
|
||||
if (calRef_ == NULL) {
|
||||
return;
|
||||
}
|
||||
for(uint i = 0; i < amdThreadTraceMemObjsNum_;++i) {
|
||||
gpu().DestroyThreadTraceBuffer(threadTraceBufferObjs_[i],i);
|
||||
}
|
||||
|
||||
// Release the thread trace reference object
|
||||
//calRef_->release();
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadTrace::create(CalThreadTraceReference* calRef)
|
||||
{
|
||||
assert(&gpu() == &calRef->gpu());
|
||||
|
||||
calRef_ = calRef;
|
||||
threadTrace_ = calRef->gslThreadTrace();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadTrace::info(uint infoType, uint* info,uint infoSize) const
|
||||
{
|
||||
switch (infoType) {
|
||||
case CL_THREAD_TRACE_BUFFERS_SIZE: {
|
||||
if (infoSize < amdThreadTraceMemObjsNum_) {
|
||||
LogError("The amount of buffers should be equal to the amount of Shader Engines");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
*info = gpu().getThreadTraceQueryRes(gslThreadTrace());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogError("Wrong ThreadTrace::getInfo parameter");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPU_THREAD_TRACE_HPP_
|
||||
#define GPU_THREAD_TRACE_HPP_
|
||||
|
||||
#include "top.hpp"
|
||||
#include "device/device.hpp"
|
||||
#include "device/gpu/gpudevice.hpp"
|
||||
|
||||
#include <vector>
|
||||
namespace gpu {
|
||||
|
||||
class VirtualGPU;
|
||||
|
||||
class CalThreadTraceReference : public amd::ReferenceCountedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
CalThreadTraceReference(
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
gslQueryObject gslThreadTrace) //!< GSL query thread trace object
|
||||
: gpu_(gpu)
|
||||
, threadTrace_(gslThreadTrace){}
|
||||
|
||||
//! Get GSL thread race object
|
||||
gslQueryObject gslThreadTrace() const { return threadTrace_; }
|
||||
|
||||
//! Returns the virtual GPU device
|
||||
const VirtualGPU& gpu() const { return gpu_; }
|
||||
|
||||
protected:
|
||||
//! Default destructor
|
||||
~CalThreadTraceReference();
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
CalThreadTraceReference(const CalThreadTraceReference&);
|
||||
|
||||
//! Disable operator=
|
||||
CalThreadTraceReference& operator=(const CalThreadTraceReference&);
|
||||
|
||||
VirtualGPU& gpu_; //!< The virtual GPU device object
|
||||
gslQueryObject threadTrace_; //!< GSL thread trace query object
|
||||
};
|
||||
|
||||
//! ThreadTrace implementation on GPU
|
||||
class ThreadTrace : public device::ThreadTrace
|
||||
{
|
||||
public:
|
||||
|
||||
//! Destructor for the GPU ThreadTrace object
|
||||
virtual ~ThreadTrace();
|
||||
|
||||
//! Creates the current object
|
||||
bool create(
|
||||
CalThreadTraceReference* calRef //!< Reference ThreadTrace
|
||||
);
|
||||
|
||||
//! Returns the GPU device, associated with the current object
|
||||
const Device& dev() const { return gpuDevice_; }
|
||||
|
||||
//! Returns the virtual GPU device
|
||||
const VirtualGPU& gpu() const { return gpu_; }
|
||||
|
||||
//! Constructor for the GPU ThreadTrace object
|
||||
ThreadTrace(
|
||||
Device& device, //!< A GPU device object
|
||||
VirtualGPU& gpu, //!< Virtual GPU device object
|
||||
uint amdThreadTraceMemObjsNum)
|
||||
: gpuDevice_(device)
|
||||
, gpu_(gpu)
|
||||
, calRef_(NULL)
|
||||
, index_(0)
|
||||
, amdThreadTraceMemObjsNum_(amdThreadTraceMemObjsNum)
|
||||
{
|
||||
threadTraceBufferObjs_ = new gslShaderTraceBufferObject[amdThreadTraceMemObjsNum];
|
||||
for (uint i = 0; i < amdThreadTraceMemObjsNum;++i) {
|
||||
threadTraceBufferObjs_[i] = gpu.CreateThreadTraceBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
//! Returns the specific information about the thread trace object
|
||||
bool info(
|
||||
uint infoType, //!< The type of returned information
|
||||
uint* info, //!< The returned information
|
||||
uint infoSize //!< The size of returned information
|
||||
) const;
|
||||
|
||||
//! Set the ThreadTrace memory buffer size
|
||||
void setMemBufferSizeTT(uint memBufferSizeTT) { memBufferSizeTT_ = memBufferSizeTT;}
|
||||
|
||||
//! Set isNewBufferBinded_ to true/false if new buffer was binded/unbinded respectively
|
||||
void setNewBufferBinded(bool isNewBufferBinded) { isNewBufferBinded_ = isNewBufferBinded; }
|
||||
|
||||
//! Attach gslMemObject to the TreadTrace buffer
|
||||
void attachMemToThreadTraceBuffer();
|
||||
|
||||
void setMemObj(size_t memObjSize,std::vector<amd::Memory*> memObj)
|
||||
{
|
||||
memObj_ = memObj;
|
||||
memBufferSizeTT_ = memObjSize;
|
||||
}
|
||||
//! Get GSL thread trace object
|
||||
gslQueryObject gslThreadTrace() const { return threadTrace_; }
|
||||
|
||||
//! Get GSL Thread Trace Buffer objects
|
||||
gslShaderTraceBufferObject* getThreadTraceBufferObjects() {return threadTraceBufferObjs_;}
|
||||
private:
|
||||
//! Disable default copy constructor
|
||||
ThreadTrace(const ThreadTrace&);
|
||||
|
||||
//! Disable default operator=
|
||||
ThreadTrace& operator=(const ThreadTrace&);
|
||||
|
||||
//! Retrieve gslMemoryObject
|
||||
gslMemObject getCurrentGslMemObject(amd::Memory* );
|
||||
|
||||
const Device& gpuDevice_; //!< The backend device
|
||||
|
||||
VirtualGPU& gpu_; //!< The virtual GPU device object
|
||||
|
||||
CalThreadTraceReference* calRef_; //!< Reference ThreadTrace
|
||||
gslShaderTraceBufferObject* threadTraceBufferObjs_; //!< The buffer object for Thread Trace recording
|
||||
uint index_; //!< ThreadTrace index in the CAL container
|
||||
uint memBufferSizeTT_; //!< ThreadTrace memory buffer size
|
||||
std::vector<amd::Memory*> memObj_; //!< ThreadTrace memory object
|
||||
gslQueryObject threadTrace_; //!< GSL thread trace query object
|
||||
uint amdThreadTraceMemObjsNum_; //!< ThreadTrace memory object`s number (should be equal to the SE number)
|
||||
bool isNewBufferBinded_; //!< The indicator if new buffer was binded to the ThreadTrace object
|
||||
bool isBufferOnSubmit_; //!< The indicator if "new buffer on submit" mode is used
|
||||
};
|
||||
|
||||
} // namespace gpu
|
||||
|
||||
#endif // GPU_THREAD_TRACE_HPP_
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include "os/os.hpp"
|
||||
#include "platform/perfctr.hpp"
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gputimestamp.hpp"
|
||||
#include "device/gpu/gpuvirtual.hpp"
|
||||
#include "device/gpu/gpucounters.hpp"
|
||||
|
||||
namespace gpu {
|
||||
|
||||
TimeStamp::TimeStamp(
|
||||
const VirtualGPU& gpu,
|
||||
gslMemObject gslMem,
|
||||
uint memOffset,
|
||||
address cpuAddr)
|
||||
: gpu_(gpu)
|
||||
, gslMem_(gslMem)
|
||||
, memOffset_(memOffset)
|
||||
{
|
||||
values_ = reinterpret_cast<volatile uint64_t*>(cpuAddr + memOffset);
|
||||
}
|
||||
|
||||
TimeStamp::~TimeStamp()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TimeStamp::begin(bool sdma)
|
||||
{
|
||||
if (!flags_.beginIssued_) {
|
||||
gpu().writeTimer(sdma, gslMem_,
|
||||
memOffset_ + CommandStartTime * sizeof(uint64_t));
|
||||
flags_.beginIssued_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimeStamp::end(bool sdma)
|
||||
{
|
||||
CondLog(!flags_.beginIssued_, "We didn't issue a begin operation!");
|
||||
gpu().writeTimer(sdma, gslMem_,
|
||||
memOffset_ + CommandEndTime * sizeof(uint64_t));
|
||||
flags_.endIssued_ = true;
|
||||
flags_.sdma_ = sdma;
|
||||
}
|
||||
|
||||
inline void
|
||||
SetValue(uint64_t* time, uint64_t val, double nanos)
|
||||
{
|
||||
*time = static_cast<uint64_t>(static_cast<double>(val) * nanos);
|
||||
}
|
||||
|
||||
void
|
||||
TimeStamp::value(uint64_t* startTime, uint64_t* endTime)
|
||||
{
|
||||
CondLog(!flags_.endIssued_, "We didn't send the counter end operation!");
|
||||
const double NanoSecondsPerTick = gpu_.dev().getAttribs().nanoSecondsPerTick;
|
||||
|
||||
SetValue(startTime, values_[CommandStartTime], NanoSecondsPerTick);
|
||||
SetValue(endTime, values_[CommandEndTime], NanoSecondsPerTick);
|
||||
}
|
||||
|
||||
TimeStampCache::~TimeStampCache()
|
||||
{
|
||||
// Release all time stamp objects from the cache
|
||||
for (uint i = 0; i < freedTS_.size(); ++i) {
|
||||
delete freedTS_[i];
|
||||
}
|
||||
freedTS_.clear();
|
||||
|
||||
// Release all memory objects
|
||||
for (uint i = 0; i < tsBuf_.size(); ++i) {
|
||||
tsBuf_[i]->unmap(&gpu_);
|
||||
delete tsBuf_[i];
|
||||
}
|
||||
tsBuf_.clear();
|
||||
|
||||
}
|
||||
|
||||
TimeStamp*
|
||||
TimeStampCache::allocTimeStamp()
|
||||
{
|
||||
TimeStamp* ts = NULL;
|
||||
if (0 != freedTS_.size()) {
|
||||
ts = freedTS_.back();
|
||||
freedTS_.pop_back();
|
||||
}
|
||||
|
||||
if (NULL == ts) {
|
||||
if ((tsBufCpu_ == NULL) || ((tsOffset_ + TimerSlotSize) > TimerBufSize)) {
|
||||
Memory* buf = new Memory(gpu_.dev(), TimerBufSize);
|
||||
if (buf == NULL || !buf->create(Resource::Remote)) {
|
||||
return NULL;
|
||||
}
|
||||
tsBufCpu_ = reinterpret_cast<address>(buf->map(&gpu_));
|
||||
memset(tsBufCpu_, 0, TimerBufSize);
|
||||
tsOffset_ = 0;
|
||||
tsBuf_.push_back(buf);
|
||||
}
|
||||
// Allocate a TimeStamp object
|
||||
ts = new TimeStamp(gpu_, tsBuf_[(tsBuf_.size() - 1)]->gslResource(),
|
||||
tsOffset_, tsBufCpu_);
|
||||
// Create a timestamp
|
||||
if (ts == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
tsOffset_ += TimerSlotSize;
|
||||
}
|
||||
|
||||
// Set this timestamp into DRM profile mode if it was requested
|
||||
ts->clearStates();
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
} // namespace gpu
|
||||
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
#ifndef GPUTIMESTAMP_HPP_
|
||||
#define GPUTIMESTAMP_HPP_
|
||||
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpuresource.hpp"
|
||||
|
||||
/*! \addtogroup GPU GPU Resource Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class VirtualGPU;
|
||||
class Memory;
|
||||
|
||||
class TimeStamp : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Enums for the timestamp information
|
||||
//! \note *4 is the limitaiton of SDMA HW
|
||||
//! (address has to be aligned by 256 bit)
|
||||
enum TimeStampValue {
|
||||
CommandStartTime = 0,
|
||||
CommandEndTime = 4,
|
||||
CommandTotal = 8
|
||||
};
|
||||
|
||||
//! The TimeStamp object flags
|
||||
union Flags
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t beginIssued_ : 1;
|
||||
uint32_t endIssued_ : 1;
|
||||
uint32_t sdma_ : 1;
|
||||
};
|
||||
uint32_t value_;
|
||||
Flags(): value_(0) {}
|
||||
};
|
||||
|
||||
//! Default constructor
|
||||
TimeStamp(
|
||||
const VirtualGPU& gpu, //!< Virtual GPU
|
||||
gslMemObject gslMem, //!< Buffer with the timer values
|
||||
uint memOffset, //!< Offset in the buffer for the current TS
|
||||
address cpuAddr //!< CPU pointer for the values in memory
|
||||
);
|
||||
|
||||
//! Default destructor
|
||||
~TimeStamp();
|
||||
|
||||
//! Starts the timestamp
|
||||
void begin(bool sdma = false);
|
||||
|
||||
//! Ends the timestamp
|
||||
void end(bool sdma = false);
|
||||
|
||||
//! Returns the timestamp result in nano seconds
|
||||
void value(uint64_t* startTime, uint64_t* endTime);
|
||||
|
||||
//! Clear all TimeStamp states
|
||||
void clearStates()
|
||||
{ flags_.value_ = 0;
|
||||
values_[CommandStartTime] = 0;
|
||||
values_[CommandEndTime] = 0;
|
||||
}
|
||||
|
||||
//! Timer commands were submitted to HW
|
||||
bool isValid() const { return (flags_.endIssued_) ? true : false; }
|
||||
|
||||
private:
|
||||
//! Disable copy constructor
|
||||
TimeStamp(const TimeStamp&);
|
||||
|
||||
//! Disable operator=
|
||||
TimeStamp& operator=(const TimeStamp&);
|
||||
|
||||
//! Returns the GPU device object
|
||||
const VirtualGPU& gpu() const { return gpu_; }
|
||||
|
||||
const VirtualGPU& gpu_; //!< Virtual GPU
|
||||
Flags flags_; //!< The time stamp state
|
||||
gslMemObject gslMem_; //!< Buffer with the timer values
|
||||
uint memOffset_; //!< Offset in the buffer for the current timer
|
||||
volatile uint64_t* values_; //!< CPU pointer to the timer values
|
||||
};
|
||||
|
||||
class TimeStampCache : public amd::HeapObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
TimeStampCache(
|
||||
VirtualGPU& gpu //!< Virtual GPU object
|
||||
)
|
||||
: gpu_(gpu)
|
||||
, tsBufCpu_(NULL)
|
||||
, tsOffset_(0) {}
|
||||
|
||||
//! Default destructor
|
||||
~TimeStampCache();
|
||||
|
||||
//! Gets a time stamp object. It will find a freed object or allocate a new one
|
||||
TimeStamp* allocTimeStamp();
|
||||
|
||||
//! Frees a time stamp object
|
||||
void freeTimeStamp(TimeStamp* ts) { freedTS_.push_back(ts); }
|
||||
|
||||
private:
|
||||
static const uint TimerSlotSize = TimeStamp::CommandTotal * sizeof(uint64_t);
|
||||
static const uint TimerBufSize = TimerSlotSize * 4096;
|
||||
|
||||
//! Disable copy constructor
|
||||
TimeStampCache(const TimeStampCache&);
|
||||
|
||||
//! Disable operator=
|
||||
TimeStampCache& operator=(const TimeStampCache&);
|
||||
|
||||
std::vector<TimeStamp*> freedTS_; //!< Array of freed time stamp objects
|
||||
VirtualGPU& gpu_; //!< Virtual GPU
|
||||
std::vector<Memory*> tsBuf_; //!< Array of memory objects with the timer value
|
||||
address tsBufCpu_; //!< CPU pointer for current TS memory
|
||||
uint tsOffset_; //!< Active offset in the current mem object
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUTIMESTAMP_HPP_*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,538 @@
|
||||
//
|
||||
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef GPUVIRTUAL_HPP_
|
||||
#define GPUVIRTUAL_HPP_
|
||||
|
||||
#include "device/gpu/gpudefs.hpp"
|
||||
#include "device/gpu/gpuconstbuf.hpp"
|
||||
#include "device/gpu/gpuprintf.hpp"
|
||||
#include "device/gpu/gputimestamp.hpp"
|
||||
#include "device/gpu/gpusched.hpp"
|
||||
#include "device/blit.hpp"
|
||||
|
||||
/*! \addtogroup GPU GPU Resource Implementation
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! GPU Device Implementation
|
||||
namespace gpu {
|
||||
|
||||
class Device;
|
||||
class Kernel;
|
||||
class Resource;
|
||||
class Memory;
|
||||
class CalCounterReference;
|
||||
class VirtualGPU;
|
||||
class Program;
|
||||
class BlitManager;
|
||||
class ThreadTrace;
|
||||
|
||||
//! Virtual GPU
|
||||
class VirtualGPU : public device::VirtualDevice, public CALGSLContext
|
||||
{
|
||||
public:
|
||||
struct CommandBatch : public amd::HeapObject
|
||||
{
|
||||
amd::Command* head_; //!< Command batch head
|
||||
GpuEvent events_[AllEngines]; //!< Last known GPU events
|
||||
TimeStamp* lastTS_; //!< TS associated with command batch
|
||||
|
||||
//! Constructor
|
||||
CommandBatch(
|
||||
amd::Command* head, //!< Command batch head
|
||||
const GpuEvent* events, //!< HW events on all engines
|
||||
TimeStamp* lastTS //!< Last TS in command batch
|
||||
): head_(head), lastTS_(lastTS)
|
||||
{
|
||||
memcpy(&events_, events, AllEngines * sizeof(GpuEvent));
|
||||
}
|
||||
};
|
||||
|
||||
//! The virtual GPU states
|
||||
union State
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint boundGlobal_ : 1; //!< Global buffer was bound
|
||||
uint profiling_ : 1; //!< Profiling is enabled
|
||||
uint forceWait_ : 1; //!< Forces wait in flush()
|
||||
uint boundCb_ : 1; //!< Constant buffer was bound
|
||||
uint boundPrintf_ : 1; //!< Printf buffer was bound
|
||||
uint hsailKernel_ : 1; //!< True if HSAIL kernel was used
|
||||
};
|
||||
uint value_;
|
||||
State(): value_(0) {}
|
||||
};
|
||||
|
||||
//! CAL descriptor for the GPU virtual device
|
||||
struct CalVirtualDesc : public amd::EmbeddedObject
|
||||
{
|
||||
ProgramGrid progGrid_; //!< CAL program grid
|
||||
uint memCount_; //!< Memory objects count
|
||||
GpuEvent events_[AllEngines]; //!< Last known GPU events
|
||||
uint iterations_; //!< Number of iterations for the execution
|
||||
TimeStamp* lastTS_; //!< Last timestamp executed on Virtual GPU
|
||||
gslMemObject constBuffers_[MaxConstBuffers];//!< Constant buffer names
|
||||
gslMemObject uavs_[MaxUavArguments]; //!< UAV bindings
|
||||
gslMemObject readImages_[MaxReadImage]; //!< Read images
|
||||
uint32_t samplersState_[MaxSamplers]; //!< State of all samplers
|
||||
};
|
||||
|
||||
typedef std::vector<ConstBuffer*> constbufs_t;
|
||||
|
||||
//! \note Legacy pre SI UAV Arena support
|
||||
static const uint UavArena = MaxWriteImage; //!< 0-7 reserved for images
|
||||
|
||||
//! GSL descriptor for the GPU kernel, specific to the virtual device
|
||||
struct GslKernelDesc : public amd::HeapObject
|
||||
{
|
||||
CALimage image_; //!< CAL image for the program
|
||||
gslProgramObject func_; //!< GSL program object
|
||||
gslMemObject intCb_; //!< Internal constant buffer
|
||||
CALUavMask uavMask_; //!< UAV mask, unclear if necessary
|
||||
CALfuncInfo funcInfo_; //!< CAL function info
|
||||
};
|
||||
|
||||
struct ResourceSlot
|
||||
{
|
||||
union State
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint bound_ : 1; //!< Resource is bound
|
||||
uint constant_ : 1; //!< Resource is a constant
|
||||
};
|
||||
uint value_;
|
||||
State(): value_(0) {}
|
||||
};
|
||||
|
||||
State state_; //!< slot's state
|
||||
Memory* memory_; //!< GPU memory object
|
||||
|
||||
ResourceSlot(): memory_(NULL) {}
|
||||
|
||||
//! Copy constructor for the kernel argument
|
||||
ResourceSlot(const ResourceSlot& data) { *this = data; }
|
||||
|
||||
//! Overloads operator=
|
||||
ResourceSlot& operator=(const ResourceSlot& data)
|
||||
{
|
||||
state_.value_ = data.state_.value_;
|
||||
memory_ = data.memory_;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class MemoryDependency : public amd::EmbeddedObject
|
||||
{
|
||||
public:
|
||||
//! Default constructor
|
||||
MemoryDependency()
|
||||
: memObjectsInQueue_(NULL)
|
||||
, numMemObjectsInQueue_(0)
|
||||
, maxMemObjectsInQueue_(0) {}
|
||||
|
||||
~MemoryDependency() { delete [] memObjectsInQueue_; }
|
||||
|
||||
//! Creates memory dependecy structure
|
||||
bool create(size_t numMemObj);
|
||||
|
||||
//! Notify the tracker about new kernel
|
||||
void newKernel() { endMemObjectsInQueue_ = numMemObjectsInQueue_; }
|
||||
|
||||
//! Validates memory object on dependency
|
||||
void validate(VirtualGPU& gpu, const Memory* memory, bool readOnly);
|
||||
|
||||
//! Clear memory dependency
|
||||
void clear(bool all = true);
|
||||
|
||||
private:
|
||||
struct MemoryState {
|
||||
uint64_t start_; //! Busy memory start address
|
||||
uint64_t end_; //! Busy memory end address
|
||||
bool readOnly_; //! Current GPU state in the queue
|
||||
};
|
||||
|
||||
MemoryState* memObjectsInQueue_; //!< Memory object state in the queue
|
||||
size_t endMemObjectsInQueue_; //!< End of mem objects in the queue
|
||||
size_t numMemObjectsInQueue_; //!< Number of mem objects in the queue
|
||||
size_t maxMemObjectsInQueue_; //!< Maximum number of mem objects in the queue
|
||||
};
|
||||
|
||||
|
||||
class DmaFlushMgmt : public amd::EmbeddedObject
|
||||
{
|
||||
public:
|
||||
DmaFlushMgmt(const Device& dev);
|
||||
|
||||
// Resets DMA command buffer workload
|
||||
void resetCbWorkload(const Device& dev);
|
||||
|
||||
// Finds split size for the current dispatch
|
||||
void findSplitSize(
|
||||
const Device& dev, //!< GPU device object
|
||||
uint64_t threads, //!< Total number of execution threads
|
||||
uint instructions //!< Number of ALU instructions
|
||||
);
|
||||
|
||||
// Returns TRUE if DMA command buffer is ready for a flush
|
||||
bool isCbReady(
|
||||
VirtualGPU& gpu, //!< Virtual GPU object
|
||||
uint64_t threads, //!< Total number of execution threads
|
||||
uint instructions //!< Number of ALU instructions
|
||||
);
|
||||
|
||||
// Returns dispatch split size
|
||||
uint dispatchSplitSize() const { return dispatchSplitSize_; }
|
||||
|
||||
private:
|
||||
uint64_t maxDispatchWorkload_; //!< Maximum number of operations for a single dispatch
|
||||
uint64_t maxCbWorkload_; //!< Maximum number of operations for DMA command buffer
|
||||
uint64_t cbWorkload_; //!< Current number of operations in DMA command buffer
|
||||
uint aluCnt_; //!< All ALUs on the chip
|
||||
uint dispatchSplitSize_; //!< Dispath split size in elements
|
||||
};
|
||||
|
||||
typedef std::vector<ResourceSlot> ResourceSlots;
|
||||
|
||||
public:
|
||||
|
||||
VirtualGPU(Device& device);
|
||||
bool create(
|
||||
bool profiling
|
||||
#if cl_amd_open_video
|
||||
, void* calVideoProperties
|
||||
#endif // cl_amd_open_video
|
||||
, uint deviceQueueSize = 0
|
||||
);
|
||||
~VirtualGPU();
|
||||
|
||||
void submitReadMemory(amd::ReadMemoryCommand& vcmd);
|
||||
void submitWriteMemory(amd::WriteMemoryCommand& vcmd);
|
||||
void submitCopyMemory(amd::CopyMemoryCommand& vcmd);
|
||||
void submitMapMemory(amd::MapMemoryCommand& vcmd);
|
||||
void submitUnmapMemory(amd::UnmapMemoryCommand& vcmd);
|
||||
void submitKernel(amd::NDRangeKernelCommand& vcmd);
|
||||
bool submitKernelInternal(
|
||||
const amd::NDRangeContainer& sizes, //!< Workload sizes
|
||||
const amd::Kernel& kernel, //!< Kernel for execution
|
||||
const_address parameters, //!< Parameters for the kernel
|
||||
bool nativeMem = true //!< Native memory objects
|
||||
);
|
||||
bool submitKernelInternalHSA(
|
||||
const amd::NDRangeContainer& sizes, //!< Workload sizes
|
||||
const amd::Kernel& kernel, //!< Kernel for execution
|
||||
const_address parameters, //!< Parameters for the kernel
|
||||
bool nativeMem = true //!< Native memory objects
|
||||
);
|
||||
void submitNativeFn(amd::NativeFnCommand& vcmd);
|
||||
void submitFillMemory(amd::FillMemoryCommand& vcmd);
|
||||
void submitMigrateMemObjects(amd::MigrateMemObjectsCommand& cmd);
|
||||
void submitMarker(amd::Marker& vcmd);
|
||||
void submitAcquireExtObjects(amd::AcquireExtObjectsCommand& vcmd);
|
||||
void submitReleaseExtObjects(amd::ReleaseExtObjectsCommand& vcmd);
|
||||
void submitPerfCounter(amd::PerfCounterCommand& vcmd);
|
||||
void submitThreadTraceMemObjects(amd::ThreadTraceMemObjectsCommand& cmd);
|
||||
void submitThreadTrace(amd::ThreadTraceCommand& vcmd);
|
||||
#if cl_amd_open_video
|
||||
void submitRunVideoProgram(amd::RunVideoProgramCommand& vcmd);
|
||||
void submitSetVideoSession(amd::SetVideoSessionCommand& cmd);
|
||||
#endif // cl_amd_open_video
|
||||
void submitSignal(amd::SignalCommand & vcmd);
|
||||
void submitMakeBuffersResident(amd::MakeBuffersResidentCommand & vcmd);
|
||||
virtual void submitSvmFreeMemory(amd::SvmFreeMemoryCommand& cmd);
|
||||
virtual void submitSvmCopyMemory(amd::SvmCopyMemoryCommand& cmd);
|
||||
virtual void submitSvmFillMemory(amd::SvmFillMemoryCommand& cmd);
|
||||
virtual void submitSvmMapMemory(amd::SvmMapMemoryCommand& cmd);
|
||||
virtual void submitSvmUnmapMemory(amd::SvmUnmapMemoryCommand& cmd);
|
||||
|
||||
void releaseMemory(gslMemObject gslResource, bool wait = true);
|
||||
void releaseKernel(CALimage calImage);
|
||||
|
||||
void flush(amd::Command* list = NULL, bool wait = false);
|
||||
bool terminate() { return true; }
|
||||
|
||||
//! Returns GPU device object associated with this kernel
|
||||
const Device& dev() const { return gpuDevice_; }
|
||||
|
||||
//! Returns CAL descriptor of the virtual device
|
||||
const CalVirtualDesc* cal() const { return &cal_; }
|
||||
|
||||
//! Returns active kernel descriptor for this virtual device
|
||||
const GslKernelDesc* gslKernelDesc() const { return activeKernelDesc_; }
|
||||
|
||||
//! Returns a GPU event, associated with GPU memory
|
||||
GpuEvent* getGpuEvent(
|
||||
const Resource* resource //!< GPU resource object
|
||||
) { return &gpuEvents_[resource->gslResource()]; }
|
||||
|
||||
//! Assigns a GPU event, associated with GPU memory
|
||||
void assignGpuEvent(
|
||||
const Resource* resource, //!< GPU resource object
|
||||
GpuEvent gpuEvent
|
||||
) { gpuEvents_[resource->gslResource()] = gpuEvent; }
|
||||
|
||||
//! Set the kernel as active
|
||||
bool setActiveKernelDesc(
|
||||
const amd::NDRangeContainer& sizes, //!< kernel execution work sizes
|
||||
const Kernel* kernel //!< GPU kernel object
|
||||
);
|
||||
|
||||
//! Set the last known GPU event
|
||||
void setGpuEvent(
|
||||
GpuEvent gpuEvent, //!< GPU event for tracking
|
||||
bool flush = false //!< TRUE if flush is required
|
||||
);
|
||||
|
||||
//! Flush DMA buffer on the specified engine
|
||||
void flushDMA(
|
||||
uint engineID //!< Engine ID for DMA flush
|
||||
);
|
||||
|
||||
//! Wait for all engines on this Virtual GPU
|
||||
//! Returns TRUE if CPU didn't wait for GPU
|
||||
bool waitAllEngines(
|
||||
CommandBatch* cb = NULL //!< Command batch
|
||||
);
|
||||
|
||||
//! Waits for the latest GPU event with a lock to prevent multiple entries
|
||||
void waitEventLock(
|
||||
CommandBatch* cb //!< Command batch
|
||||
);
|
||||
|
||||
//! Returns a resource associated with the constant buffer
|
||||
const ConstBuffer* cb(uint idx) const { return constBufs_[idx]; }
|
||||
|
||||
//! Adds CAL objects into the constant buffer vector
|
||||
void addConstBuffer(ConstBuffer* cb) { constBufs_.push_back(cb); }
|
||||
|
||||
constbufs_t constBufs_; //!< constant buffers
|
||||
|
||||
//! Returns a resource associated with the constant buffer
|
||||
ConstBuffer* numGrpCb() const { return numGrpCb_; }
|
||||
|
||||
//! Start the command profiling
|
||||
void profilingBegin(
|
||||
amd::Command& command, //!< Command queue object
|
||||
bool drmProfiling = false //!< Measure DRM time
|
||||
);
|
||||
|
||||
//! End the command profiling
|
||||
void profilingEnd(amd::Command& command);
|
||||
|
||||
//! Collect the profiling results
|
||||
bool profilingCollectResults(
|
||||
CommandBatch* cb, //!< Command batch
|
||||
const amd::Event* waitingEvent //!< Waiting event
|
||||
);
|
||||
|
||||
//! Adds a memory handle into the GSL memory array for Virtual Heap
|
||||
bool addVmMemory(
|
||||
const Resource* resource //!< GPU resource object
|
||||
);
|
||||
|
||||
//! Adds a stage write buffer into a list
|
||||
void addXferWrite(Resource& resource);
|
||||
|
||||
//! Adds a pinned memory object into a map
|
||||
void addPinnedMem(amd::Memory* mem);
|
||||
|
||||
//! Release pinned memory objects
|
||||
void releasePinnedMem();
|
||||
|
||||
//! Returns gsl memory object for VM
|
||||
const gslMemObject* vmMems() const { return vmMems_; }
|
||||
|
||||
//! Returns the monitor object for execution access by VirtualGPU
|
||||
amd::Monitor& execution() { return execution_; }
|
||||
|
||||
//! Returns the virtual gpu unique index
|
||||
uint index() const { return index_; }
|
||||
|
||||
//! Get the PrintfDbg object
|
||||
PrintfDbg& printfDbg() const { return *printfDbg_; }
|
||||
|
||||
//! Get the PrintfDbgHSA object
|
||||
PrintfDbgHSA& printfDbgHSA() const { return *printfDbgHSA_; }
|
||||
|
||||
//! Enables synchronized transfers
|
||||
void enableSyncedBlit() const;
|
||||
|
||||
//! Checks if profiling is enabled
|
||||
bool profiling() const { return state_.profiling_; }
|
||||
|
||||
//! Returns memory dependency class
|
||||
MemoryDependency& memoryDependency() { return memoryDependency_; }
|
||||
|
||||
//! Returns hsaQueueMem_
|
||||
const Memory* hsaQueueMem() const { return hsaQueueMem_;}
|
||||
|
||||
//! Returns DMA flush management structure
|
||||
const DmaFlushMgmt& dmaFlushMgmt() const { return dmaFlushMgmt_; }
|
||||
|
||||
//! Releases GSL memory objects allocated on this queue
|
||||
void releaseMemObjects();
|
||||
|
||||
//! Returns the HW ring used on this virtual device
|
||||
uint hwRing() const { return hwRing_; }
|
||||
|
||||
//! Returns current timestamp object for profiling
|
||||
TimeStamp* currTs() const { return cal_.lastTS_; }
|
||||
|
||||
//! Returns virtual queue object for device enqueuing
|
||||
Memory* vQueue() const { return virtualQueue_; }
|
||||
|
||||
//! Update virtual queue header
|
||||
void writeVQueueHeader(VirtualGPU& hostQ, uint64_t kernelTable);
|
||||
|
||||
EngineType engineID_; //!< Engine ID for this VirtualGPU
|
||||
ResourceSlots slots_; //!< Resource slots for kernel arguments
|
||||
State state_; //!< virtual GPU current state
|
||||
CalVirtualDesc cal_; //!< CAL virtual device descriptor
|
||||
|
||||
protected:
|
||||
virtual void profileEvent(EngineType engine, bool type) const;
|
||||
|
||||
//! Creates buffer object from image
|
||||
amd::Memory* createBufferFromImage(
|
||||
amd::Memory& amdImage //! The parent image object(untiled images only)
|
||||
) const;
|
||||
|
||||
private:
|
||||
typedef std::map<CALimage, GslKernelDesc*> GslKernels;
|
||||
typedef std::map<gslMemObject, GpuEvent> GpuEvents;
|
||||
|
||||
//! Finds total amount of necessary iterations
|
||||
inline void findIterations(
|
||||
const amd::NDRangeContainer& sizes, //!< Original workload sizes
|
||||
const amd::NDRange& local, //!< Local workgroup size
|
||||
amd::NDRange& groups, //!< Calculated workgroup sizes
|
||||
amd::NDRange& remainder, //!< Calculated remainder sizes
|
||||
size_t& extra //!< Amount of extra executions for remainder
|
||||
);
|
||||
|
||||
//! Setups workloads for the current iteration
|
||||
inline void setupIteration(
|
||||
uint iteration, //!< Current iteration
|
||||
const amd::NDRangeContainer& sizes, //!< Original workload sizes
|
||||
Kernel& gpuKernel, //!< GPU kernel
|
||||
amd::NDRange& global, //!< Global size for the current iteration
|
||||
amd::NDRange& offsets, //!< Offsets for the current iteration
|
||||
amd::NDRange& local, //!< Local sizes for the current iteration
|
||||
amd::NDRange& groups, //!< Group sizes for the current iteration
|
||||
amd::NDRange& groupOffset, //!< Group offsets for the current iteration
|
||||
amd::NDRange& divider, //!< Group divider
|
||||
amd::NDRange& remainder, //!< Remain workload
|
||||
size_t extra //!< Extra groups
|
||||
);
|
||||
|
||||
//! Allocates constant buffers
|
||||
bool allocConstantBuffers();
|
||||
|
||||
//! Allocates CAL kernel descriptor of the virtual device
|
||||
GslKernelDesc* allocKernelDesc(
|
||||
const Kernel* kernel, //!< Kernel object
|
||||
CALimage calImage); //!< CAL image
|
||||
|
||||
//! Frees CAL kernel descriptor of the virtual device
|
||||
void freeKernelDesc(GslKernelDesc* desc);
|
||||
|
||||
bool gslOpen(uint nEngines, gslEngineDescriptor *engines);
|
||||
void gslDestroy();
|
||||
|
||||
//! Releases stage write buffers
|
||||
void releaseXferWrite();
|
||||
|
||||
//! Allocate hsaQueueMem_
|
||||
bool allocHsaQueueMem();
|
||||
|
||||
//! Awaits a command batch with a waiting event
|
||||
bool awaitCompletion(
|
||||
CommandBatch* cb, //!< Command batch for to wait
|
||||
const amd::Event* waitingEvent = NULL //!< A waiting event
|
||||
);
|
||||
|
||||
//! Validates the scratch buffer memory for a specified kernel
|
||||
void validateScratchBuffer(
|
||||
const Kernel* kernel //!< Kernel for validaiton
|
||||
);
|
||||
|
||||
//! Detects memory dependency for HSAIL kernels and flushes caches
|
||||
void processMemObjectsHSA(
|
||||
const amd::Kernel& kernel, //!< AMD kernel object for execution
|
||||
const_address params, //!< Pointer to the param's store
|
||||
bool nativeMem //!< Native memory objects
|
||||
);
|
||||
|
||||
//! Common function for fill memory used by both svm Fill and non-svm fill
|
||||
bool fillMemory(
|
||||
cl_command_type type, //!< the command type
|
||||
amd::Memory* amdMemory, //!< memory object to fill
|
||||
const void* pattern, //!< pattern to fill the memory
|
||||
size_t patternSize, //!< pattern size
|
||||
const amd::Coord3D& origin, //!< memory origin
|
||||
const amd::Coord3D& size //!< memory size for filling
|
||||
);
|
||||
|
||||
bool copyMemory(
|
||||
cl_command_type type, //!< the command type
|
||||
amd::Memory& srcMem, //!< source memory object
|
||||
amd::Memory& dstMem, //!< destination memory object
|
||||
bool entire, //!< flag of entire memory copy
|
||||
const amd::Coord3D& srcOrigin, //!< source memory origin
|
||||
const amd::Coord3D& dstOrigin, //!< destination memory object
|
||||
const amd::Coord3D& size, //!< copy size
|
||||
const amd::BufferRect& srcRect, //!< region of source for copy
|
||||
const amd::BufferRect& dstRect //!< region of destination for copy
|
||||
);
|
||||
|
||||
//! Returns TRUE if virtual queue was successfully allocatted
|
||||
bool createVirtualQueue(
|
||||
uint deviceQueueSize //!< Device queue size
|
||||
);
|
||||
|
||||
GslKernels gslKernels_; //!< GSL kernel descriptors
|
||||
GslKernelDesc* activeKernelDesc_; //!< active GSL kernel descriptors
|
||||
GpuEvents gpuEvents_; //!< GPU events
|
||||
|
||||
Device& gpuDevice_; //!< physical GPU device
|
||||
amd::Monitor execution_; //!< Lock to serialise access to all device objects
|
||||
uint index_; //!< The virtual device unique index
|
||||
|
||||
PrintfDbg* printfDbg_; //!< GPU printf implemenation
|
||||
PrintfDbgHSA* printfDbgHSA_; //!< HSAIL printf implemenation
|
||||
|
||||
TimeStampCache* tsCache_; //!< TimeStamp cache
|
||||
MemoryDependency memoryDependency_; //!< Memory dependency class
|
||||
|
||||
gslMemObject* vmMems_; //!< Array of GSL memories for VM mode
|
||||
uint numVmMems_; //!< Number of entries in VM mem array
|
||||
|
||||
DmaFlushMgmt dmaFlushMgmt_; //!< DMA flush management
|
||||
|
||||
std::list<Resource*> xferWriteBuffers_; //!< Stage write buffers
|
||||
std::list<amd::Memory*> pinnedMems_;//!< Pinned memory list
|
||||
|
||||
typedef std::list<CommandBatch*> CommandBatchList;
|
||||
CommandBatchList cbList_; //!< List of command batches
|
||||
|
||||
ConstBuffer* numGrpCb_; //!< Constant buffer for 8xx workaround
|
||||
uint scratchRegNum_; //!< Number of scratch registers used in this queue
|
||||
uint hwRing_; //!< HW ring used on this virtual device
|
||||
|
||||
uint64_t readjustTimeGPU_; //!< Readjust time between GPU and CPU timestamps
|
||||
TimeStamp* currTs_; //!< current timestamp for command
|
||||
|
||||
AmdVQueueHeader* vqHeader_; //!< Sysmem copy for virtual queue header
|
||||
Memory* virtualQueue_; //!< Virtual device queue
|
||||
Memory* schedParams_; //!< The scheduler parameters
|
||||
uint schedParamIdx_; //!< Index in the scheduler parameters buffer
|
||||
|
||||
Memory* hsaQueueMem_; //!< Memory for the amd_queue_t object
|
||||
};
|
||||
|
||||
/*@}*/} // namespace gpu
|
||||
|
||||
#endif /*GPUVIRTUAL_HPP_*/
|
||||
@@ -0,0 +1,2 @@
|
||||
OPENCL_DEPTH = $(CAL_DEPTH)/../../../..
|
||||
include $(OPENCL_DEPTH)/runtime/runtimedefs
|
||||
@@ -0,0 +1 @@
|
||||
include $(OPENCL_DEPTH)/runtime/runtimerules
|
||||
@@ -0,0 +1,304 @@
|
||||
/**
|
||||
* @file cal.h
|
||||
* @brief CAL Interface Header
|
||||
* @version 1.00.0 Beta
|
||||
*/
|
||||
|
||||
|
||||
/* ============================================================
|
||||
|
||||
Copyright (c) 2007 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use of this material is permitted under the following
|
||||
conditions:
|
||||
|
||||
Redistributions must retain the above copyright notice and all terms of this
|
||||
license.
|
||||
|
||||
In no event shall anyone redistributing or accessing or using this material
|
||||
commence or participate in any arbitration or legal action relating to this
|
||||
material against Advanced Micro Devices, Inc. or any copyright holders or
|
||||
contributors. The foregoing shall survive any expiration or termination of
|
||||
this license or any agreement or access or use related to this material.
|
||||
|
||||
ANY BREACH OF ANY TERM OF THIS LICENSE SHALL RESULT IN THE IMMEDIATE REVOCATION
|
||||
OF ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL.
|
||||
|
||||
THIS MATERIAL IS PROVIDED BY ADVANCED MICRO DEVICES, INC. AND ANY COPYRIGHT
|
||||
HOLDERS AND CONTRIBUTORS "AS IS" IN ITS CURRENT CONDITION AND WITHOUT ANY
|
||||
REPRESENTATIONS, GUARANTEE, OR WARRANTY OF ANY KIND OR IN ANY WAY RELATED TO
|
||||
SUPPORT, INDEMNITY, ERROR FREE OR UNINTERRUPTED OPERATION, OR THAT IT IS FREE
|
||||
FROM DEFECTS OR VIRUSES. ALL OBLIGATIONS ARE HEREBY DISCLAIMED - WHETHER
|
||||
EXPRESS, IMPLIED, OR STATUTORY - INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
ACCURACY, COMPLETENESS, OPERABILITY, QUALITY OF SERVICE, OR NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, REVENUE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED OR BASED ON ANY THEORY OF LIABILITY
|
||||
ARISING IN ANY WAY RELATED TO THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE. THE ENTIRE AND AGGREGATE LIABILITY OF ADVANCED MICRO DEVICES,
|
||||
INC. AND ANY COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT EXCEED TEN DOLLARS
|
||||
(US $10.00). ANYONE REDISTRIBUTING OR ACCESSING OR USING THIS MATERIAL ACCEPTS
|
||||
THIS ALLOCATION OF RISK AND AGREES TO RELEASE ADVANCED MICRO DEVICES, INC. AND
|
||||
ANY COPYRIGHT HOLDERS AND CONTRIBUTORS FROM ANY AND ALL LIABILITIES,
|
||||
OBLIGATIONS, CLAIMS, OR DEMANDS IN EXCESS OF TEN DOLLARS (US $10.00). THE
|
||||
FOREGOING ARE ESSENTIAL TERMS OF THIS LICENSE AND, IF ANY OF THESE TERMS ARE
|
||||
CONSTRUED AS UNENFORCEABLE, FAIL IN ESSENTIAL PURPOSE, OR BECOME VOID OR
|
||||
DETRIMENTAL TO ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR
|
||||
CONTRIBUTORS FOR ANY REASON, THEN ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE
|
||||
THIS MATERIAL SHALL TERMINATE IMMEDIATELY. MOREOVER, THE FOREGOING SHALL
|
||||
SURVIVE ANY EXPIRATION OR TERMINATION OF THIS LICENSE OR ANY AGREEMENT OR
|
||||
ACCESS OR USE RELATED TO THIS MATERIAL.
|
||||
|
||||
NOTICE IS HEREBY PROVIDED, AND BY REDISTRIBUTING OR ACCESSING OR USING THIS
|
||||
MATERIAL SUCH NOTICE IS ACKNOWLEDGED, THAT THIS MATERIAL MAY BE SUBJECT TO
|
||||
RESTRICTIONS UNDER THE LAWS AND REGULATIONS OF THE UNITED STATES OR OTHER
|
||||
COUNTRIES, WHICH INCLUDE BUT ARE NOT LIMITED TO, U.S. EXPORT CONTROL LAWS SUCH
|
||||
AS THE EXPORT ADMINISTRATION REGULATIONS AND NATIONAL SECURITY CONTROLS AS
|
||||
DEFINED THEREUNDER, AS WELL AS STATE DEPARTMENT CONTROLS UNDER THE U.S.
|
||||
MUNITIONS LIST. THIS MATERIAL MAY NOT BE USED, RELEASED, TRANSFERRED, IMPORTED,
|
||||
EXPORTED AND/OR RE-EXPORTED IN ANY MANNER PROHIBITED UNDER ANY APPLICABLE LAWS,
|
||||
INCLUDING U.S. EXPORT CONTROL LAWS REGARDING SPECIFICALLY DESIGNATED PERSONS,
|
||||
COUNTRIES AND NATIONALS OF COUNTRIES SUBJECT TO NATIONAL SECURITY CONTROLS.
|
||||
MOREOVER, THE FOREGOING SHALL SURVIVE ANY EXPIRATION OR TERMINATION OF ANY
|
||||
LICENSE OR AGREEMENT OR ACCESS OR USE RELATED TO THIS MATERIAL.
|
||||
|
||||
NOTICE REGARDING THE U.S. GOVERNMENT AND DOD AGENCIES: This material is
|
||||
provided with "RESTRICTED RIGHTS" and/or "LIMITED RIGHTS" as applicable to
|
||||
computer software and technical data, respectively. Use, duplication,
|
||||
distribution or disclosure by the U.S. Government and/or DOD agencies is
|
||||
subject to the full extent of restrictions in all applicable regulations,
|
||||
including those found at FAR52.227 and DFARS252.227 et seq. and any successor
|
||||
regulations thereof. Use of this material by the U.S. Government and/or DOD
|
||||
agencies is acknowledgment of the proprietary rights of any copyright holders
|
||||
and contributors, including those of Advanced Micro Devices, Inc., as well as
|
||||
the provisions of FAR52.227-14 through 23 regarding privately developed and/or
|
||||
commercial computer software.
|
||||
|
||||
This license forms the entire agreement regarding the subject matter hereof and
|
||||
supersedes all proposals and prior discussions and writings between the parties
|
||||
with respect thereto. This license does not affect any ownership, rights, title,
|
||||
or interest in, or relating to, this material. No terms of this license can be
|
||||
modified or waived, and no breach of this license can be excused, unless done
|
||||
so in a writing signed by all affected parties. Each term of this license is
|
||||
separately enforceable. If any term of this license is determined to be or
|
||||
becomes unenforceable or illegal, such term shall be reformed to the minimum
|
||||
extent necessary in order for this license to remain in effect in accordance
|
||||
with its terms as modified by such reformation. This license shall be governed
|
||||
by and construed in accordance with the laws of the State of Texas without
|
||||
regard to rules on conflicts of law of any state or jurisdiction or the United
|
||||
Nations Convention on the International Sale of Goods. All disputes arising out
|
||||
of this license shall be subject to the jurisdiction of the federal and state
|
||||
courts in Austin, Texas, and all defenses are hereby waived concerning personal
|
||||
jurisdiction and venue of these courts.
|
||||
|
||||
============================================================ */
|
||||
|
||||
#ifndef __CAL_H__
|
||||
#define __CAL_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void CALvoid; /**< void type */
|
||||
typedef char CALchar; /**< ASCII character */
|
||||
typedef signed char CALbyte; /**< 1 byte signed integer value */
|
||||
typedef unsigned char CALubyte; /**< 1 byte unsigned integer value */
|
||||
typedef signed short CALshort; /**< 2 byte signed integer value */
|
||||
typedef unsigned short CALushort; /**< 2 byte unsigned integer value */
|
||||
typedef signed int CALint; /**< 4 byte signed integer value */
|
||||
typedef unsigned int CALuint; /**< 4 byte unsigned intger value */
|
||||
typedef float CALfloat; /**< 32-bit IEEE floating point value */
|
||||
typedef double CALdouble; /**< 64-bit IEEE floating point value */
|
||||
typedef signed long CALlong; /**< long value */
|
||||
typedef unsigned long CALulong; /**< unsigned long value */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
typedef signed __int64 CALint64; /**< 8 byte signed integer value */
|
||||
typedef unsigned __int64 CALuint64; /**< 8 byte unsigned integer value */
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
typedef signed long long CALint64; /**< 8 byte signed integer value */
|
||||
typedef unsigned long long CALuint64; /**< 8 byte unsigned integer value */
|
||||
|
||||
#else
|
||||
#error "Unsupported compiler type."
|
||||
#endif
|
||||
|
||||
/** Boolean type */
|
||||
typedef enum CALbooleanEnum {
|
||||
CAL_FALSE = 0, /**< Boolean false value */
|
||||
CAL_TRUE = 1 /**< Boolean true value */
|
||||
} CALboolean;
|
||||
|
||||
/** Device Kernel ISA */
|
||||
typedef enum CALtargetEnum {
|
||||
CAL_TARGET_600, /**< R600 GPU ISA */
|
||||
CAL_TARGET_610, /**< RV610 GPU ISA */
|
||||
CAL_TARGET_630, /**< RV630 GPU ISA */
|
||||
CAL_TARGET_670, /**< RV670 GPU ISA */
|
||||
CAL_TARGET_7XX, /**< R700 class GPU ISA */
|
||||
CAL_TARGET_770, /**< RV770 GPU ISA */
|
||||
CAL_TARGET_710, /**< RV710 GPU ISA */
|
||||
CAL_TARGET_730, /**< RV730 GPU ISA */
|
||||
CAL_TARGET_CYPRESS, /**< CYPRESS GPU ISA */
|
||||
CAL_TARGET_JUNIPER, /**< JUNIPER GPU ISA */
|
||||
CAL_TARGET_REDWOOD, /**< REDWOOD GPU ISA */
|
||||
CAL_TARGET_CEDAR, /**< CEDAR GPU ISA */
|
||||
//##BEGIN_PRIVATE##
|
||||
CAL_TARGET_SUMO, /**< SUMO GPU ISA */
|
||||
CAL_TARGET_SUPERSUMO, /**< SUPERSUMO GPU ISA */
|
||||
CAL_TARGET_WRESTLER, /**< WRESTLER GPU ISA */
|
||||
CAL_TARGET_CAYMAN, /**< CAYMAN GPU ISA */
|
||||
CAL_TARGET_KAUAI, /**< KAUAI GPU ISA */
|
||||
CAL_TARGET_BARTS , /**< BARTS GPU ISA */
|
||||
CAL_TARGET_TURKS , /**< TURKS GPU ISA */
|
||||
CAL_TARGET_CAICOS, /**< CAICOS GPU ISA */
|
||||
CAL_TARGET_TAHITI, /**< TAHITI GPU ISA*/
|
||||
CAL_TARGET_PITCAIRN, /**< PITCAIRN GPU ISA*/
|
||||
CAL_TARGET_CAPEVERDE, /**< CAPE VERDE GPU ISA*/
|
||||
CAL_TARGET_DEVASTATOR, /**< DEVASTATOR GPU ISA*/
|
||||
CAL_TARGET_SCRAPPER, /**< SCRAPPER GPU ISA*/
|
||||
CAL_TARGET_OLAND, /**< OLAND GPU ISA*/
|
||||
CAL_TARGET_BONAIRE, /**< BONAIRE GPU ISA*/
|
||||
CAL_TARGET_SPECTRE, /**< KAVERI1 GPU ISA*/
|
||||
CAL_TARGET_SPOOKY, /**< KAVERI2 GPU ISA*/
|
||||
CAL_TARGET_KALINDI, /**< KALINDI GPU ISA*/
|
||||
CAL_TARGET_HAINAN, /**< HAINAN GPU ISA*/
|
||||
CAL_TARGET_HAWAII, /**< HAWAII GPU ISA*/
|
||||
CAL_TARGET_ICELAND, /**< ICELAND GPU ISA*/
|
||||
CAL_TARGET_TONGA, /**< TONGA GPU ISA*/
|
||||
CAL_TARGET_GODAVARI, /**< MULLINS GPU ISA*/
|
||||
CAL_TARGET_BERMUDA, /**< BERMUDA GPU ISA*/
|
||||
CAL_TARGET_FIJI, /**< FIJI GPU ISA*/
|
||||
CAL_TARGET_CARRIZO, /**< CARRIZO GPU ISA*/
|
||||
CAL_TARGET_LAST = CAL_TARGET_CARRIZO, /**< last */
|
||||
//##END_PRIVATE##
|
||||
} CALtarget;
|
||||
|
||||
/** CAL image container */
|
||||
typedef struct CALimageRec* CALimage;
|
||||
|
||||
#define CAL_ASIC_INFO_MAX_LEN 128
|
||||
|
||||
/** CAL computational domain */
|
||||
typedef struct CALdomainRec {
|
||||
CALuint x; /**< x origin of domain */
|
||||
CALuint y; /**< y origin of domain */
|
||||
CALuint width; /**< width of domain */
|
||||
CALuint height; /**< height of domain */
|
||||
} CALdomain;
|
||||
|
||||
/** CAL device attributes */
|
||||
typedef struct CALdeviceattribsRec {
|
||||
CALuint struct_size; /**< Client filled out size of CALdeviceattribs struct */
|
||||
CALtarget target; /**< Asic identifier */
|
||||
CALuint localRAM; /**< Amount of local GPU RAM in megabytes */
|
||||
CALuint uncachedRemoteRAM; /**< Amount of uncached remote GPU memory in megabytes */
|
||||
CALuint cachedRemoteRAM; /**< Amount of cached remote GPU memory in megabytes */
|
||||
CALuint engineClock; /**< GPU device clock rate in megahertz */
|
||||
CALuint memoryClock; /**< GPU memory clock rate in megahertz */
|
||||
CALuint wavefrontSize; /**< Wavefront size */
|
||||
CALuint numberOfSIMD; /**< Number of SIMDs */
|
||||
bool doublePrecision; /**< double precision supported */
|
||||
bool localDataShare; /**< local data share supported */
|
||||
bool globalDataShare; /**< global data share supported */
|
||||
bool globalGPR; /**< global GPR supported */
|
||||
bool computeShader; /**< compute shader supported */
|
||||
bool memExport; /**< memexport supported */
|
||||
CALuint pitch_alignment; /**< Required alignment for calCreateRes allocations (in data elements) */
|
||||
CALuint surface_alignment; /**< Required start address alignment for calCreateRes allocations (in bytes) */
|
||||
CALuint numberOfUAVs; /**< Number of UAVs */
|
||||
bool bUAVMemExport; /**< Hw only supports mem export to simulate 1 UAV */
|
||||
CALuint numberOfShaderEngines; /**< Number of shader engines */
|
||||
CALuint targetRevision; /**< Asic family revision */
|
||||
CALuint totalVisibleHeap; /**< Amount of visible local GPU RAM in megabytes */
|
||||
CALuint totalInvisibleHeap; /**< Amount of invisible local GPU RAM in megabytes */
|
||||
CALuint totalDirectHeap; /**< Amount of direct GPU memory in megabytes */
|
||||
CALuint totalCoherentHeap; /**< Amount of coherent GPU memory in megabytes */
|
||||
CALuint totalRemoteSharedHeap; /**< Amount of remote Shared GPU memory in megabytes */
|
||||
CALuint totalCachedRemoteSharedHeap; /**< Amount of cached remote Shared GPU memory in megabytes */
|
||||
CALuint totalSDIHeap; /**< Amount of SDI memory allocated in CCC */
|
||||
CALuint pciTopologyInformation; /**< PCI topology information contains: bus, device and function number. */
|
||||
CALchar boardName[CAL_ASIC_INFO_MAX_LEN]; /**< Actual ASIC board name and not the internal name. */
|
||||
bool vectorBufferInstructionAddr64; /**< Vector buffer instructions support ADDR64 mode */
|
||||
bool memRandomAccessTargetInstructions; /**< hw/sc supports memory RAT (Random Access Target) instructions e.g. mem0.x_z_ supported */
|
||||
CALuint memBusWidth; /**< Memory busw width */
|
||||
CALuint numMemBanks; /**< Number of memory banks */
|
||||
CALuint counterFreq; /**< Ref clock counter frequency */
|
||||
double nanoSecondsPerTick; /**< Nano seconds per GPU tick */
|
||||
bool longIdleDetect; /**< Whether LongIdleDetect enabled */
|
||||
bool priSupport; /**< IOMMUv2 ATS/PRI support */
|
||||
CALuint64 vaStart; /**< VA start address */
|
||||
CALuint64 vaEnd; /**< VA end address */
|
||||
bool isWorkstation; /**< Whether Device is a Workstation/Server part */
|
||||
} CALdeviceattribs;
|
||||
|
||||
/** CAL device status */
|
||||
typedef struct CALdevicestatusRec {
|
||||
CALuint struct_size; /**< Client filled out size of CALdevicestatus struct */
|
||||
CALuint availLocalRAM; /**< Amount of available local GPU RAM in megabytes */
|
||||
CALuint availUncachedRemoteRAM; /**< Amount of available uncached remote GPU memory in megabytes */
|
||||
CALuint availCachedRemoteRAM; /**< Amount of available cached remote GPU memory in megabytes */
|
||||
CALuint availVisibleHeap; /**< Amount of available visible local GPU RAM in megabytes */
|
||||
CALuint availInvisibleHeap; /**< Amount of available invisible local GPU RAM in megabytes */
|
||||
CALuint availDirectHeap; /**< Amount of available direct GPU memory in megabytes */
|
||||
CALuint availCoherentHeap; /**< Amount of available coherent GPU memory in megabytes */
|
||||
CALuint availRemoteSharedHeap; /**< Amount of available remote Shared GPU memory in megabytes */
|
||||
CALuint availCachedRemoteSharedHeap; /**< Amount of available cached remote Shared GPU memory in megabytes */
|
||||
CALuint largestBlockVisibleHeap; /**< Largest block available visible local GPU RAM in megabytes */
|
||||
CALuint largestBlockInvisibleHeap; /**< Largest block available invisible local GPU RAM in megabytes */
|
||||
CALuint largestBlockRemoteHeap; /**< Largest block available remote GPU memory in megabytes */
|
||||
CALuint largestBlockCachedRemoteHeap; /**< Largest block available cached remote GPU memory in megabytes */
|
||||
CALuint largestBlockDirectHeap; /**< Largest block available direct GPU memory in megabytes */
|
||||
CALuint largestBlockCoherentHeap; /**< Largest block available coherent GPU memory in megabytes */
|
||||
CALuint largestBlockRemoteSharedHeap; /**< Largest block available remote Shared GPU memory in megabytes */
|
||||
CALuint largestBlockCachedRemoteSharedHeap; /**< Largest block available cached remote Shared GPU memory in megabytes */
|
||||
} CALdevicestatus;
|
||||
|
||||
/** CAL resource allocation flags **/
|
||||
typedef enum CALresallocflagsEnum {
|
||||
CAL_RESALLOC_GLOBAL_BUFFER = 1, /**< used for global import/export buffer */
|
||||
} CALresallocflags;
|
||||
|
||||
|
||||
/** CAL function information **/
|
||||
typedef struct CALfuncInfoRec
|
||||
{
|
||||
CALuint maxScratchRegsNeeded; /**< Maximum number of scratch regs needed */
|
||||
CALuint numSharedGPRUser; /**< Number of shared GPRs */
|
||||
CALuint numSharedGPRTotal; /**< Number of shared GPRs including ones used by SC */
|
||||
bool eCsSetupMode; /**< Slow mode */
|
||||
CALuint numThreadPerGroup; /**< Flattend umber of threads per group */
|
||||
CALuint numThreadPerGroupX; /**< x dimension of numThreadPerGroup */
|
||||
CALuint numThreadPerGroupY; /**< y dimension of numThreadPerGroup */
|
||||
CALuint numThreadPerGroupZ; /**< z dimension of numThreadPerGroup */
|
||||
CALuint totalNumThreadGroup; /**< Total number of thread groups */
|
||||
CALuint numWavefrontPerSIMD; /**< Number of wavefronts per SIMD */
|
||||
bool isMaxNumWavePerSIMD; /**< Is this the max num active wavefronts per SIMD */
|
||||
bool setBufferForNumGroup; /**< Need to set up buffer for info on number of thread groups? */
|
||||
CALuint wavefrontSize; /**< number of threads per wavefront. */
|
||||
CALuint numGPRsAvailable; /**< number of GPRs available to the program */
|
||||
CALuint numGPRsUsed; /**< number of GPRs used by the program */
|
||||
CALuint LDSSizeAvailable; /**< LDS size available to the program */
|
||||
CALuint LDSSizeUsed; /**< LDS size used by the program */
|
||||
CALuint stackSizeAvailable; /**< stack size availabe to the program */
|
||||
CALuint stackSizeUsed; /**< stack size use by the program */
|
||||
CALuint numSGPRsAvailable; /**< number of SGPRs available to the program */
|
||||
CALuint numSGPRsUsed; /**< number of SGPRs used by the program */
|
||||
CALuint numVGPRsAvailable; /**< number of VGPRs available to the program */
|
||||
CALuint numVGPRsUsed; /**< number of VGPRs used by the program */
|
||||
} CALfuncInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __CAL_H__ */
|
||||
|
||||
@@ -0,0 +1,660 @@
|
||||
/**
|
||||
* @file calcl.h
|
||||
* @brief CAL Compiler Interface Header
|
||||
* @version 1.00.0 Beta
|
||||
*/
|
||||
|
||||
|
||||
/* ============================================================
|
||||
|
||||
Copyright (c) 2007 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use of this material is permitted under the following
|
||||
conditions:
|
||||
|
||||
Redistributions must retain the above copyright notice and all terms of this
|
||||
license.
|
||||
|
||||
In no event shall anyone redistributing or accessing or using this material
|
||||
commence or participate in any arbitration or legal action relating to this
|
||||
material against Advanced Micro Devices, Inc. or any copyright holders or
|
||||
contributors. The foregoing shall survive any expiration or termination of
|
||||
this license or any agreement or access or use related to this material.
|
||||
|
||||
ANY BREACH OF ANY TERM OF THIS LICENSE SHALL RESULT IN THE IMMEDIATE REVOCATION
|
||||
OF ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE THIS MATERIAL.
|
||||
|
||||
THIS MATERIAL IS PROVIDED BY ADVANCED MICRO DEVICES, INC. AND ANY COPYRIGHT
|
||||
HOLDERS AND CONTRIBUTORS "AS IS" IN ITS CURRENT CONDITION AND WITHOUT ANY
|
||||
REPRESENTATIONS, GUARANTEE, OR WARRANTY OF ANY KIND OR IN ANY WAY RELATED TO
|
||||
SUPPORT, INDEMNITY, ERROR FREE OR UNINTERRUPTED OPERATION, OR THAT IT IS FREE
|
||||
FROM DEFECTS OR VIRUSES. ALL OBLIGATIONS ARE HEREBY DISCLAIMED - WHETHER
|
||||
EXPRESS, IMPLIED, OR STATUTORY - INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
ACCURACY, COMPLETENESS, OPERABILITY, QUALITY OF SERVICE, OR NON-INFRINGEMENT.
|
||||
IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, REVENUE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED OR BASED ON ANY THEORY OF LIABILITY
|
||||
ARISING IN ANY WAY RELATED TO THIS MATERIAL, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE. THE ENTIRE AND AGGREGATE LIABILITY OF ADVANCED MICRO DEVICES,
|
||||
INC. AND ANY COPYRIGHT HOLDERS AND CONTRIBUTORS SHALL NOT EXCEED TEN DOLLARS
|
||||
(US $10.00). ANYONE REDISTRIBUTING OR ACCESSING OR USING THIS MATERIAL ACCEPTS
|
||||
THIS ALLOCATION OF RISK AND AGREES TO RELEASE ADVANCED MICRO DEVICES, INC. AND
|
||||
ANY COPYRIGHT HOLDERS AND CONTRIBUTORS FROM ANY AND ALL LIABILITIES,
|
||||
OBLIGATIONS, CLAIMS, OR DEMANDS IN EXCESS OF TEN DOLLARS (US $10.00). THE
|
||||
FOREGOING ARE ESSENTIAL TERMS OF THIS LICENSE AND, IF ANY OF THESE TERMS ARE
|
||||
CONSTRUED AS UNENFORCEABLE, FAIL IN ESSENTIAL PURPOSE, OR BECOME VOID OR
|
||||
DETRIMENTAL TO ADVANCED MICRO DEVICES, INC. OR ANY COPYRIGHT HOLDERS OR
|
||||
CONTRIBUTORS FOR ANY REASON, THEN ALL RIGHTS TO REDISTRIBUTE, ACCESS OR USE
|
||||
THIS MATERIAL SHALL TERMINATE IMMEDIATELY. MOREOVER, THE FOREGOING SHALL
|
||||
SURVIVE ANY EXPIRATION OR TERMINATION OF THIS LICENSE OR ANY AGREEMENT OR
|
||||
ACCESS OR USE RELATED TO THIS MATERIAL.
|
||||
|
||||
NOTICE IS HEREBY PROVIDED, AND BY REDISTRIBUTING OR ACCESSING OR USING THIS
|
||||
MATERIAL SUCH NOTICE IS ACKNOWLEDGED, THAT THIS MATERIAL MAY BE SUBJECT TO
|
||||
RESTRICTIONS UNDER THE LAWS AND REGULATIONS OF THE UNITED STATES OR OTHER
|
||||
COUNTRIES, WHICH INCLUDE BUT ARE NOT LIMITED TO, U.S. EXPORT CONTROL LAWS SUCH
|
||||
AS THE EXPORT ADMINISTRATION REGULATIONS AND NATIONAL SECURITY CONTROLS AS
|
||||
DEFINED THEREUNDER, AS WELL AS STATE DEPARTMENT CONTROLS UNDER THE U.S.
|
||||
MUNITIONS LIST. THIS MATERIAL MAY NOT BE USED, RELEASED, TRANSFERRED, IMPORTED,
|
||||
EXPORTED AND/OR RE-EXPORTED IN ANY MANNER PROHIBITED UNDER ANY APPLICABLE LAWS,
|
||||
INCLUDING U.S. EXPORT CONTROL LAWS REGARDING SPECIFICALLY DESIGNATED PERSONS,
|
||||
COUNTRIES AND NATIONALS OF COUNTRIES SUBJECT TO NATIONAL SECURITY CONTROLS.
|
||||
MOREOVER, THE FOREGOING SHALL SURVIVE ANY EXPIRATION OR TERMINATION OF ANY
|
||||
LICENSE OR AGREEMENT OR ACCESS OR USE RELATED TO THIS MATERIAL.
|
||||
|
||||
NOTICE REGARDING THE U.S. GOVERNMENT AND DOD AGENCIES: This material is
|
||||
provided with "RESTRICTED RIGHTS" and/or "LIMITED RIGHTS" as applicable to
|
||||
computer software and technical data, respectively. Use, duplication,
|
||||
distribution or disclosure by the U.S. Government and/or DOD agencies is
|
||||
subject to the full extent of restrictions in all applicable regulations,
|
||||
including those found at FAR52.227 and DFARS252.227 et seq. and any successor
|
||||
regulations thereof. Use of this material by the U.S. Government and/or DOD
|
||||
agencies is acknowledgment of the proprietary rights of any copyright holders
|
||||
and contributors, including those of Advanced Micro Devices, Inc., as well as
|
||||
the provisions of FAR52.227-14 through 23 regarding privately developed and/or
|
||||
commercial computer software.
|
||||
|
||||
This license forms the entire agreement regarding the subject matter hereof and
|
||||
supersedes all proposals and prior discussions and writings between the parties
|
||||
with respect thereto. This license does not affect any ownership, rights, title,
|
||||
or interest in, or relating to, this material. No terms of this license can be
|
||||
modified or waived, and no breach of this license can be excused, unless done
|
||||
so in a writing signed by all affected parties. Each term of this license is
|
||||
separately enforceable. If any term of this license is determined to be or
|
||||
becomes unenforceable or illegal, such term shall be reformed to the minimum
|
||||
extent necessary in order for this license to remain in effect in accordance
|
||||
with its terms as modified by such reformation. This license shall be governed
|
||||
by and construed in accordance with the laws of the State of Texas without
|
||||
regard to rules on conflicts of law of any state or jurisdiction or the United
|
||||
Nations Convention on the International Sale of Goods. All disputes arising out
|
||||
of this license shall be subject to the jurisdiction of the federal and state
|
||||
courts in Austin, Texas, and all defenses are hereby waived concerning personal
|
||||
jurisdiction and venue of these courts.
|
||||
|
||||
============================================================ */
|
||||
|
||||
#ifndef __CALCL_H__
|
||||
#define __CALCL_H__
|
||||
|
||||
#include "cal.h"
|
||||
#include "gsl_enum.h"
|
||||
#include "gsl_types.h"
|
||||
#include "cm_enum.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct ProgramGridRec
|
||||
{
|
||||
gslDomain3D gridBlock; /**< size of a block of data */
|
||||
gslDomain3D gridSize; /**< size of 'blocks' to execute. */
|
||||
gslDomain3D partialGridBlock;/** Partial grid block */
|
||||
CALuint localSize; /** size of OpenCL Local Memory in bytes */
|
||||
} ProgramGrid;
|
||||
|
||||
// flags for calCtxWaitForEvents
|
||||
typedef enum CALwaitTypeEnum
|
||||
{
|
||||
CAL_WAIT_POLLING = 0,
|
||||
CAL_WAIT_LOW_CPU_UTILIZATION = 1,
|
||||
} CALwaitType;
|
||||
|
||||
//
|
||||
// calResAllocView typedefs
|
||||
//
|
||||
typedef enum CALresallocviewflagsRec {
|
||||
CAL_RESALLOCVIEW_GLOBAL_BUFFER = CAL_RESALLOC_GLOBAL_BUFFER, /**< used for global import/export buffer */
|
||||
CAL_RESALLOCVIEW_LINEAR_ALIGNED = CAL_RESALLOC_GLOBAL_BUFFER, /**< 256 byte alignment restriction. */
|
||||
CAL_RESALLOCVIEW_LINEAR_UNALIGNED = 3, /**< no alignment restrictions */
|
||||
} CALresallocviewflags;
|
||||
|
||||
typedef struct CALresourceDescRec {
|
||||
gslMemObjectAttribLocation type;
|
||||
gslResource3D size;
|
||||
cmSurfFmt format;
|
||||
gslChannelOrder channelOrder;
|
||||
gslMemObjectAttribType dimension;
|
||||
CALuint mipLevels;
|
||||
CALvoid* systemMemory;
|
||||
CALuint flags;
|
||||
CALuint systemMemorySize;
|
||||
CALuint64 busAddress[2];
|
||||
mcaddr vaBase;
|
||||
gslMemObjectAttribSection section;
|
||||
} CALresourceDesc;
|
||||
|
||||
typedef enum CALresallocsliceviewflagsRec {
|
||||
CAL_RESALLOCSLICEVIEW_GLOBAL_BUFFER = CAL_RESALLOC_GLOBAL_BUFFER, /**< used for global import/export buffer */
|
||||
CAL_RESALLOCSLICEVIEW_LINEAR_ALIGNED = CAL_RESALLOC_GLOBAL_BUFFER, /**< 256 byte alignment restriction. */
|
||||
CAL_RESALLOCSLICEVIEW_LINEAR_UNALIGNED = CAL_RESALLOCVIEW_LINEAR_UNALIGNED, /**< no alignment restrictions */
|
||||
CAL_RESALLOCSLICEVIEW_LEVEL = 0x10, /**< sliceDesc.layer is not used, the whole level is only*/
|
||||
CAL_RESALLOCSLICEVIEW_LAYER = 0x20, /**< sliceDesc.layer is not used, the whole level is only*/
|
||||
CAL_RESALLOCSLICEVIEW_LEVEL_AND_LAYER = CAL_RESALLOCSLICEVIEW_LEVEL | CAL_RESALLOCSLICEVIEW_LAYER,
|
||||
} CALresallocsliceviewflags;
|
||||
|
||||
//
|
||||
// Thread Trace Extension
|
||||
//
|
||||
|
||||
typedef struct CALthreadTraceConfigRec CALthreadTraceConfig;
|
||||
|
||||
//
|
||||
// Video Extension
|
||||
//
|
||||
|
||||
typedef struct CALvideoPropertiesRec CALvideoProperties;
|
||||
typedef struct CALprogramVideoRec CALprogramVideo;
|
||||
typedef struct CALdeviceVideoAttribsRec CALdeviceVideoAttribs;
|
||||
typedef struct CALcontextPropertiesRec CALcontextProperties;
|
||||
typedef struct CALprogramVideoDecodeRec CALprogramVideoDecode;
|
||||
typedef struct CALprogramVideoEncodeRec CALprogramVideoEncode;
|
||||
typedef struct CALvideoAttribRec CALvideoAttrib;
|
||||
typedef struct CALvideoEncAttribRec CALvideoEncAttrib;
|
||||
|
||||
// VCE
|
||||
typedef struct CALEncodeCreateVCERec CALEncodeCreateVCE;
|
||||
typedef struct CALEncodeGetDeviceInfoRec CALEncodeGetDeviceInfo;
|
||||
typedef struct CALEncodeGetNumberOfModesRec CALEncodeGetNumberOfModes;
|
||||
typedef struct CALEncodeGetModesRec CALEncodeGetModes;
|
||||
typedef struct CALEncodeGetDeviceCAPRec CALEncodeGetDeviceCAP;
|
||||
typedef struct CALEncodeSetStateRec CALEncodeSetState;
|
||||
typedef struct CALEncodeGetPictureControlConfigRec CALEncodeGetPictureControlConfig;
|
||||
typedef struct CALEncodeGetRateControlConfigRec CALEncodeGetRateControlConfig;
|
||||
typedef struct CALEncodeGetMotionEstimationConfigRec CALEncodeGetMotionEstimationConfig;
|
||||
typedef struct CALEncodeGetRDOControlConfigRec CALEncodeGetRDOControlConfig;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_NV12_INTERLEAVED = 1,// NV12
|
||||
CAL_VID_YV12_INTERLEAVED, // YV12
|
||||
} CALdecodeFormat;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_H264_BASELINE = 1, // H.264 bitstream acceleration baseline profile
|
||||
CAL_VID_H264_MAIN, // H.264 bitstream acceleration main profile
|
||||
CAL_VID_H264_HIGH, // H.264 bitstream acceleration high profile
|
||||
CAL_VID_VC1_SIMPLE, // VC-1 bitstream acceleration simple profile
|
||||
CAL_VID_VC1_MAIN, // VC-1 bitstream acceleration main profile
|
||||
CAL_VID_VC1_ADVANCED, // VC-1 bitstream acceleration advanced profile
|
||||
CAL_VID_MPEG2_VLD, // MPEG2 bitstream acceleration VLD profile
|
||||
} CALdecodeProfile;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_ENC_H264_BASELINE = 1, // H.264 bitstream acceleration baseline profile
|
||||
CAL_VID_ENC_H264_MAIN, // H.264 bitstream acceleration main profile
|
||||
CAL_VID_ENC_H264_HIGH, // H.264 bitstream acceleration high profile
|
||||
} CALencodeProfile;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_CONTEXT_VIDEO = 1,
|
||||
CAL_CONTEXT_3DCOMPUTE = 2,
|
||||
CAL_CONTEXT_COMPUTE0 = 3,
|
||||
CAL_CONTEXT_COMPUTE1 = 4,
|
||||
CAL_CONTEXT_DRMDMA0 = 5,
|
||||
CAL_CONTEXT_DRMDMA1 = 6,
|
||||
CAL_CONTEXT_VIDEO_VCE,
|
||||
CALcontextEnum_FIRST = CAL_CONTEXT_VIDEO,
|
||||
CALcontextEnum_LAST = CAL_CONTEXT_VIDEO_VCE,
|
||||
} CALcontextEnum;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_PRIORITY_NEUTRAL = 0,
|
||||
CAL_PRIORITY_HIGH = 1,
|
||||
CAL_PRIORITY_LOW = 2
|
||||
} CALpriorityEnum;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VIDEO_DECODE = 1,
|
||||
CAL_VIDEO_ENCODE = 2
|
||||
} CALvideoType;
|
||||
|
||||
struct CALcontextPropertiesRec
|
||||
{
|
||||
CALcontextEnum name;
|
||||
CALpriorityEnum priority;
|
||||
CALvoid* data;
|
||||
};
|
||||
|
||||
struct CALthreadTraceConfigRec
|
||||
{
|
||||
CALuint cu; // target compute unit [cu]
|
||||
CALuint sh; // target shader array [sh],that contains target cu
|
||||
CALuint simd_mask; // bitmask to enable or disable target tokens for different SIMDs
|
||||
CALuint vm_id_mask; // virtual memory [vm] IDs to capture
|
||||
CALuint token_mask; // bitmask indicating which trace token IDs will be included in the trace
|
||||
CALuint reg_mask; // bitmask indicating which register types should be included in the trace
|
||||
CALuint inst_mask; // types of instruction scheduling updates which should be recorded
|
||||
CALuint random_seed; // linear feedback shift register [LFSR] seed
|
||||
CALuint user_data; // user data ,which is written as payload
|
||||
CALuint capture_mode; // indicator for the way how THREAD_TRACE_START / STOP events affect token collection
|
||||
CALboolean is_user_data; // indicator if user_data is set
|
||||
CALboolean is_wrapped; // indicator if the memory buffer should be wrapped around instead of stopping at the end
|
||||
};
|
||||
|
||||
struct CALvideoPropertiesRec
|
||||
{
|
||||
CALuint size;
|
||||
CALuint flags;
|
||||
CALdecodeProfile profile;
|
||||
CALdecodeFormat format;
|
||||
CALuint width;
|
||||
CALuint height;
|
||||
CALcontextEnum VideoEngine_name;
|
||||
};
|
||||
|
||||
struct CALprogramVideoRec
|
||||
{
|
||||
CALuint size;
|
||||
CALvideoType type;
|
||||
CALuint flags;
|
||||
};
|
||||
|
||||
struct CALprogramVideoDecodeRec
|
||||
{
|
||||
CALprogramVideo videoType;
|
||||
void* picture_parameter_1;
|
||||
void* picture_parameter_2;
|
||||
CALuint picture_parameter_2_size;
|
||||
void* bitstream_data;
|
||||
CALuint bitstream_data_size;
|
||||
void* slice_data_control;
|
||||
CALuint slice_data_size;
|
||||
};
|
||||
|
||||
struct CALprogramVideoEncodeRec
|
||||
{
|
||||
CALprogramVideo videoType;
|
||||
CALuint pictureParam1Size;
|
||||
CALuint pictureParam2Size;
|
||||
void* pictureParam1;
|
||||
void* pictureParam2;
|
||||
CALuint uiTaskID;
|
||||
};
|
||||
|
||||
struct CALvideoAttribRec
|
||||
{
|
||||
CALdecodeProfile decodeProfile;
|
||||
CALdecodeFormat decodeFormat;
|
||||
};
|
||||
|
||||
struct CALvideoEncAttribRec
|
||||
{
|
||||
CALencodeProfile encodeProfile;
|
||||
CALdecodeFormat encodeFormat; // decode format is the same as the encode format
|
||||
};
|
||||
|
||||
struct CALdeviceVideoAttribsRec
|
||||
{
|
||||
CALuint data_size; // in - size of the struct,
|
||||
// out - bytes of data incl. pointed to
|
||||
CALuint max_decode_sessions;
|
||||
const CALvideoAttrib* video_attribs; // list of supported
|
||||
// profile/format pairs
|
||||
const CALvideoEncAttrib* video_enc_attribs;
|
||||
};
|
||||
|
||||
|
||||
////// VCE
|
||||
struct CALEncodeCreateVCERec
|
||||
{
|
||||
CALvoid* VCEsession;
|
||||
};
|
||||
|
||||
struct CALEncodeGetDeviceInfoRec
|
||||
{
|
||||
unsigned int device_id;
|
||||
unsigned int max_encode_stream;
|
||||
unsigned int encode_cap_list_size;
|
||||
};
|
||||
|
||||
struct CALEncodeGetNumberOfModesRec
|
||||
{
|
||||
unsigned int num_of_encode_Mode;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_encode_MODE_NONE = 0,
|
||||
CAL_VID_encode_AVC_FULL = 1,
|
||||
CAL_VID_encode_AVC_ENTROPY = 2,
|
||||
} CALencodeMode;
|
||||
|
||||
struct CALEncodeGetModesRec
|
||||
{
|
||||
CALuint NumEncodeModesToRetrieve;
|
||||
CALencodeMode *pEncodeModes;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_ENCODE_JOB_PRIORITY_NONE = 0,
|
||||
CAL_VID_ENCODE_JOB_PRIORITY_LEVEL1 = 1, // Always in normal queue
|
||||
CAL_VID_ENCODE_JOB_PRIORITY_LEVEL2 = 2 // possibly in low-latency queue
|
||||
} CAL_VID_ENCODE_JOB_PRIORITY;
|
||||
|
||||
typedef struct _CAL_VID_PROFILE_LEVEL
|
||||
{
|
||||
CALuint profile; //based on H.264 standard
|
||||
CALuint level;
|
||||
} CAL_VID_PROFILE_LEVEL;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_PICTURE_NONOE = 0,
|
||||
CAL_VID_PICTURE_NV12 = 1,
|
||||
} CAL_VID_PICTURE_FORMAT;
|
||||
|
||||
#define CAL_VID_MAX_NUM_PICTURE_FORMATS_H264_AVC 10
|
||||
#define CAL_VID_MAX_NUM_PROFILE_LEVELS_H264_AVC 20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint maxPicSizeInMBs; // Max picture size in MBs
|
||||
CALuint minPicSizeInMBs; // Min picture size in MBs
|
||||
CALuint numPictureFormats; // number of supported picture formats
|
||||
CAL_VID_PICTURE_FORMAT supportedPictureFormats[CAL_VID_MAX_NUM_PICTURE_FORMATS_H264_AVC];
|
||||
CALuint numProfileLevels; // number of supported profiles/levels returne;
|
||||
CAL_VID_PROFILE_LEVEL supportedProfileLevel[CAL_VID_MAX_NUM_PROFILE_LEVELS_H264_AVC];
|
||||
CALuint maxBitRate; // Max bit rate
|
||||
CALuint minBitRate; // min bit rate
|
||||
CAL_VID_ENCODE_JOB_PRIORITY supportedJobPriority;// supported max level of job priority
|
||||
}CAL_VID_ENCODE_CAPS_FULL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CAL_VID_ENCODE_JOB_PRIORITY supportedJobPriority;// supported max level of job priority
|
||||
CALuint maxJobQueueDepth; // Max job queue depth
|
||||
}CAL_VID_ENCODE_CAPS_ENTROPY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALencodeMode EncodeModes;
|
||||
CALuint encode_cap_size;
|
||||
union
|
||||
{
|
||||
CAL_VID_ENCODE_CAPS_FULL *encode_cap_full;
|
||||
CAL_VID_ENCODE_CAPS_ENTROPY *encode_cap_entropy;
|
||||
void *encode_cap;
|
||||
} caps;
|
||||
} CAL_VID_ENCODE_CAPS;
|
||||
|
||||
struct CALEncodeGetDeviceCAPRec
|
||||
{
|
||||
CALuint num_of_encode_cap;
|
||||
CAL_VID_ENCODE_CAPS *encode_caps;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID__ENCODE_STATE_START = 1,
|
||||
CAL_VID__ENCODE_STATE_PAUSE = 2,
|
||||
CAL_VID__ENCODE_STATE_RESUME = 3,
|
||||
CAL_VID__ENCODE_STATE_STOP = 4
|
||||
} CAL_VID_ENCODE_STATE ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size
|
||||
|
||||
CALuint useConstrainedIntraPred; // binary var - force the use of constrained intra prediction when set to 1
|
||||
//CABAC options
|
||||
CALuint cabacEnable; // Enable CABAC entropy coding
|
||||
CALuint cabacIDC; // cabac_init_id = 0; cabac_init_id = 1; cabac_init_id = 2;
|
||||
|
||||
CALuint loopFilterDisable; // binary var - disable loop filter when 1 - enable loop filter when 0 (0 and 1 are the only two supported cases)
|
||||
int encLFBetaOffset; // -- move with loop control flag , Loop filter control, slice_beta_offset (N.B. only used if deblocking filter is not disabled, and there is no div2 as defined in the h264 bitstream syntax)
|
||||
int encLFAlphaC0Offset; // Loop filter control, slice_alpha_c0_offset (N.B. only used if deblocking filter is not disabled, and there is no div2 as defined in the h264 bitstream syntax)
|
||||
CALuint encIDRPeriod;
|
||||
CALuint encIPicPeriod; // spacing for I pictures, in case driver doesnt force/select a picture type, this will be used for inference
|
||||
int encHeaderInsertionSpacing; // spacing for inserting SPS/PPS. Example usage cases are: 0 for inserting at the beginning of the stream only, 1 for every picture, "GOP size" to align it with GOP boundaries etc. For compliance reasons, these headers might be inserted when SPS/PPS parameters change from the config packages.
|
||||
CALuint encCropLeftOffset;
|
||||
CALuint encCropRightOffset;
|
||||
CALuint encCropTopOffset;
|
||||
CALuint encCropBottomOffset;
|
||||
CALuint encNumMBsPerSlice; // replaces encSliceArgument - Slice control - number of MBs per slice
|
||||
CALuint encNumSlicesPerFrame; // Slice control - number of slices in this frame, pre-calculated to avoid DIV operation in firmware
|
||||
CALuint encForceIntraRefresh; // 1 serves to load intra refresh bitmap from address force_intra_refresh_bitmap_mc_addr when equal to 1, 3 also loads dirty clean bitmap on top of the intra refresh
|
||||
CALuint encForceIMBPeriod; // --- package with intra referesh -Intra MB spacing. if encForceIntraRefresh = 2, shifts intra refreshed MBs by frame number
|
||||
CALuint encInsertVUIParam; // insert VUI params in SPS
|
||||
CALuint encInsertSEIMsg; // insert SEI messages (bit 0 for buffering period; bit 1 for picture timing; bit 2 for pan scan)
|
||||
} CAL_VID_ENCODE_PICTURE_CONTROL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size
|
||||
CALuint encRateControlMethod; // rate control method to be used
|
||||
CALuint encRateControlTargetBitRate; // target bit rate
|
||||
CALuint encRateControlPeakBitRate; // peak bit rate
|
||||
CALuint encRateControlFrameRateNumerator; // target frame rate
|
||||
CALuint encGOPSize; // RC GOP size
|
||||
CALuint encRCOptions; // packed bitfield definition for extending options here, bit 0: RC will not generate skipped frames in order to meet GOP target, bits 1-30: up for grabs by the RC alg designer
|
||||
CALuint encQP_I; // I frame quantization only if rate control is disabled
|
||||
CALuint encQP_P; // P frame quantization if rate control is disabled
|
||||
CALuint encQP_B; // B frame quantization if rate control is disabled
|
||||
CALuint encVBVBufferSize; // VBV buffer size - this is CPB Size, and the default is per Table A-1 of the spec
|
||||
CALuint encRateControlFrameRateDenominator;// target frame rate
|
||||
} CAL_VID_ENCODE_RATE_CONTROL;
|
||||
|
||||
// mode estimation control options
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size
|
||||
CALuint imeDecimationSearch; // decimation search is on
|
||||
CALuint motionEstHalfPixel; // enable half pel motion estimation
|
||||
CALuint motionEstQuarterPixel; // enable quarter pel motion estimation
|
||||
CALuint disableFavorPMVPoint; // disable favorization of PMV point
|
||||
CALuint forceZeroPointCenter; // force [0,0] point as search window center in IME
|
||||
CALuint lsmVert; // Luma Search window in MBs, set to either VCE_ENC_SEARCH_WIND_5x3 or VCE_ENC_SEARCH_WIND_9x5 or VCE_ENC_SEARCH_WIND_13x7
|
||||
CALuint encSearchRangeX; // forward prediction - Manual limiting of horizontal motion vector range (for performance) in pel resolution
|
||||
CALuint encSearchRangeY; // forward prediction - Manual limiting of vertical motion vector range (for performance)
|
||||
CALuint encSearch1RangeX; // for 2nd ref - curr IME_SEARCH_SIZE doesn't have SIZE__SEARCH1_X bitfield
|
||||
CALuint encSearch1RangeY; // for 2nd ref
|
||||
CALuint disable16x16Frame1; // second reference (B frame) limitation
|
||||
CALuint disableSATD; // Disable SATD cost calculation (SAD only)
|
||||
CALuint enableAMD; // FME advanced mode decision
|
||||
CALuint encDisableSubMode; // --- FME
|
||||
CALuint encIMESkipX; // sub sample search window horz --- UENC_IME_OPTIONS.SKIP_POINT_X
|
||||
CALuint encIMESkipY; // sub sample search window vert --- UENC_IME_OPTIONS.SKIP_POINT_Y
|
||||
CALuint encEnImeOverwDisSubm; // Enable overwriting of fme_disable_submode in IME with enabled mode number equal to ime_overw_dis_subm_no (only 8x8 and above could be enabled)
|
||||
CALuint encImeOverwDisSubmNo; // Numbers of mode IME will pick if en_ime_overw_dis_subm equal to 1.
|
||||
CALuint encIME2SearchRangeX; // IME Additional Search Window Size: horizontal 1-4 (+- this value left and right from center)
|
||||
CALuint encIME2SearchRangeY; // IME Additional Search Window Size: vertical not-limited (+- this value up and down from center)
|
||||
// (+- this value up and down from center)
|
||||
} CAL_VID_ENCODE_MOTION_ESTIMATION_CONTROL; // structure aligned to 88 bytes
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size
|
||||
CALuint encDisableTbePredIFrame; // Disable Prediction Modes For I-Frames
|
||||
CALuint encDisableTbePredPFrame; // same as above for P frames
|
||||
CALuint useFmeInterpolY; // zero_residues_luma
|
||||
CALuint useFmeInterpolUV; // zero_residues_chroma
|
||||
CALuint enc16x16CostAdj; // --- UENC_FME_MD.M16x16_COST_ADJ
|
||||
CALuint encSkipCostAdj; // --- UENC_FME_MD.MSkip_COST_ADJ
|
||||
unsigned char encForce16x16skip;
|
||||
} CAL_VID_ENCODE_RDO_CONTROL;
|
||||
|
||||
|
||||
struct CALEncodeSetStateRec
|
||||
{
|
||||
CAL_VID_ENCODE_STATE encode_states;
|
||||
};
|
||||
struct CALEncodeGetPictureControlConfigRec
|
||||
{
|
||||
CAL_VID_ENCODE_PICTURE_CONTROL encode_picture_control;
|
||||
};
|
||||
struct CALEncodeGetRateControlConfigRec
|
||||
{
|
||||
CAL_VID_ENCODE_RATE_CONTROL encode_rate;
|
||||
};
|
||||
struct CALEncodeGetMotionEstimationConfigRec
|
||||
{
|
||||
CAL_VID_ENCODE_MOTION_ESTIMATION_CONTROL encode_motion_estimation;
|
||||
};
|
||||
struct CALEncodeGetRDOControlConfigRec
|
||||
{
|
||||
CAL_VID_ENCODE_RDO_CONTROL encode_RDO;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_CONFIG_TYPE_NONE = 0,
|
||||
CAL_VID_CONFIG_TYPE_PICTURECONTROL = 1,
|
||||
CAL_VID_CONFIG_TYPE_RATECONTROL = 2,
|
||||
CAL_VID_CONFIG_TYPE_MOTIONSESTIMATION = 3,
|
||||
CAL_VID_CONFIG_TYPE_RDO = 4
|
||||
} CAL_VID_CONFIG_TYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CAL_VID_CONFIG_TYPE configType;
|
||||
union
|
||||
{
|
||||
CAL_VID_ENCODE_PICTURE_CONTROL* pPictureControl;
|
||||
CAL_VID_ENCODE_RATE_CONTROL* pRateControl;
|
||||
CAL_VID_ENCODE_MOTION_ESTIMATION_CONTROL* pMotionEstimation;
|
||||
CAL_VID_ENCODE_RDO_CONTROL* pRDO;
|
||||
} config;
|
||||
} CAL_VID_CONFIG;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_PICTURE_STRUCTURE_H264_NONE = 0,
|
||||
CAL_VID_PICTURE_STRUCTURE_H264_FRAME = 1,
|
||||
CAL_VID_PICTURE_STRUCTURE_H264_TOP_FIELD = 2,
|
||||
CAL_VID_PICTURE_STRUCTURE_H264_BOTTOM_FIELD = 3
|
||||
} CAL_VID_PICTURE_STRUCTURE_H264;
|
||||
|
||||
// Used to force picture type
|
||||
typedef enum _CU_VID_PICTURE_TYPE_H264
|
||||
{
|
||||
CAL_VID_PICTURE_TYPE_H264_NONE = 0,
|
||||
CAL_VID_PICTURE_TYPE_H264_SKIP = 1,
|
||||
CAL_VID_PICTURE_TYPE_H264_IDR = 2,
|
||||
CAL_VID_PICTURE_TYPE_H264_I = 3,
|
||||
CAL_VID_PICTURE_TYPE_H264_P = 4
|
||||
} CAL_VID_PICTURE_TYPE_H264;
|
||||
|
||||
typedef union _CAL_VID_ENCODE_PARAMETERS_H264_FLAGS
|
||||
{
|
||||
struct
|
||||
{
|
||||
// enable/disable features
|
||||
unsigned int reserved : 32; // reserved fields must be set to zero
|
||||
} flags;
|
||||
unsigned int value;
|
||||
}CAL_VID_ENCODE_PARAMETERS_H264_FLAGS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size. Must be always set to the size of AVE_ENCODE_PARAMETERS_H264.
|
||||
|
||||
CAL_VID_ENCODE_PARAMETERS_H264_FLAGS flags; // enable/disable any supported features
|
||||
|
||||
CALboolean insertSPS;
|
||||
CAL_VID_PICTURE_STRUCTURE_H264 pictureStructure;
|
||||
CALboolean forceRefreshMap;
|
||||
CALuint forceIMBPeriod;
|
||||
CAL_VID_PICTURE_TYPE_H264 forcePicType;
|
||||
} CAL_VID_ENCODE_PARAMETERS_H264;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_BUFFER_TYPE_NONE = 0,
|
||||
CAL_VID_BUFFER_TYPE_ENCODE_PARAM_H264 = 1,
|
||||
CAL_VID_BUFFER_TYPE_PICTURE = 2,
|
||||
CAL_VID_BUFFER_TYPE_SLICE_HEADER = 3,
|
||||
CAL_VID_BUFFER_TYPE_SLICE = 4,
|
||||
CAL_VID_BUFFER_TYPE_RECONSTRUCTED_PICTURE_OUTPUT = 5
|
||||
} CAL_VID_BUFFER_TYPE;
|
||||
|
||||
#define CAL_VID_SURFACE_HANDLE void*
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CAL_VID_BUFFER_TYPE bufferType;
|
||||
union
|
||||
{
|
||||
CAL_VID_ENCODE_PARAMETERS_H264* pEncodeParamH264;
|
||||
CAL_VID_SURFACE_HANDLE pPicture;
|
||||
CAL_VID_SURFACE_HANDLE pSliceHeader;
|
||||
CAL_VID_SURFACE_HANDLE pSlice;
|
||||
CAL_VID_SURFACE_HANDLE pReconstructedPictureOutput;
|
||||
|
||||
} buffer;
|
||||
} CAL_VID_BUFFER_DESCRIPTION;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAL_VID_TASK_STATUS_NONE = 0,
|
||||
CAL_VID_TASK_STATUS_COMPLETE = 1, // encoding task has finished successfully.
|
||||
CAL_VID_TASK_STATUS_FAILED = 2 // encoding task has finished but failed.
|
||||
} CAL_VID_TASK_STATUS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CALuint size; // structure size
|
||||
CALuint taskID; // task ID
|
||||
CAL_VID_TASK_STATUS status; // Task status. May be duplicated if current task has multiple output blocks.
|
||||
CALuint size_of_bitstream_data; // data size of the output block
|
||||
void* bitstream_data; // read pointer the top portion of the generated bitstream data for the current task
|
||||
} CAL_VID_OUTPUT_DESCRIPTION;
|
||||
|
||||
typedef enum CALmemcopyflagsEnum
|
||||
{
|
||||
CAL_MEMCOPY_DEFAULT = 0, /**< default CAL behavior of partial sync */
|
||||
CAL_MEMCOPY_SYNC = 1, /**< used to synchronize with the specified CAL context */
|
||||
CAL_MEMCOPY_ASYNC = 2, /**< used to indicate completely asynchronous behavior */
|
||||
} CALmemcopyflags;
|
||||
|
||||
typedef enum CALResGLBufferTypeEnum{
|
||||
CAL_RES_GL_BUFFER_TYPE_TEXTURE = 0,
|
||||
CAL_RES_GL_BUFFER_TYPE_FRAMEBUFFER = 1,
|
||||
CAL_RES_GL_BUFFER_TYPE_RENDERBUFFER = 2,
|
||||
CAL_RES_GL_BUFFER_TYPE_VERTEXBUFFER = 3
|
||||
}CALResGLBufferType;
|
||||
|
||||
typedef struct CALDeviceGLParamsRec {
|
||||
CALvoid *GLplatformContext;
|
||||
CALvoid *GLdeviceContext;
|
||||
CALuint flags;
|
||||
} CALDeviceGLParams;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __CALCL_H__ */
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
* Trade secret of ATI Technologies, Inc.
|
||||
* Copyright 2006, ATI Technologies, Inc., (unpublished)
|
||||
*
|
||||
* All rights reserved. This notice is intended as a precaution against
|
||||
* inadvertent publication and does not imply publication or any waiver
|
||||
* of confidentiality. The year included in the foregoing notice is the
|
||||
* year of creation of the work.
|
||||
*
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __CALIF_H__
|
||||
#define __CALIF_H__
|
||||
|
||||
#define CALIF_VERSION_MAJOR 1
|
||||
#define CALIF_VERSION_MINOR 1
|
||||
|
||||
#define CALIF_HELPER_SURF_WIDTH 256
|
||||
#define CALIF_HELPER_SURF_HEIGHT 8
|
||||
|
||||
#define CALIF_SEMAPHORE_SURF_WIDTH 8
|
||||
#define CALIF_SEMAPHORE_SURF_HEIGHT 1
|
||||
|
||||
|
||||
|
||||
// Structure for commuticating with driver through Lock backdoor
|
||||
typedef struct _CALIF_LOCK_COMM_HEADER
|
||||
{
|
||||
UINT uCmd;
|
||||
UINT *puRes;
|
||||
|
||||
PVOID pInputBuffer;
|
||||
UINT uInputBufferSize;
|
||||
|
||||
PVOID pOutputBuffer;
|
||||
UINT uOutputBufferSize;
|
||||
|
||||
} CALIF_LOCK_COMM_HEADER, *PCALIF_LOCK_COMM_HEADER;
|
||||
|
||||
|
||||
|
||||
// Commands for LOCK backdoor
|
||||
typedef enum _CALIF_LOCK_CMD
|
||||
{
|
||||
CALIF_LOCK_CMD_GET_VERSION = 1,
|
||||
CALIF_LOCK_CMD_NEXT_SURF_INFO = 2,
|
||||
CALIF_LOCK_CMD_GET_SURF_INFO = 3,
|
||||
CALIF_LOCK_CMD_SET_ALIAS_INFO = 4,
|
||||
CALIF_LOCK_CMD_SET_CAL_TARGET = 5,
|
||||
CALIF_LOCK_CMD_GET_CAL_STATUS = 6,
|
||||
CALIF_LOCK_CMD_GET_RENDER_STATUS = 7,
|
||||
CALIF_LOCK_CMD_INVALID = 0xFFFFFFFF,
|
||||
} CALIF_LOCK_CMD;
|
||||
|
||||
|
||||
typedef enum _CALIF_LOCK_CMD_RES
|
||||
{
|
||||
CALIF_LOCK_CMD_RES_OK = 0,
|
||||
CALIF_LOCK_CMD_RES_ERROR = 1,
|
||||
CALIF_LOCK_CMD_RES_INVALID = 0xFFFFFFFF,
|
||||
} CALIF_LOCK_CMD_RES;
|
||||
|
||||
|
||||
|
||||
// Input structure
|
||||
typedef struct _CALIF_CAL_TARGET
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
ULONG ulNumTargets;
|
||||
ULONG ulTargets[MAX_CAL_TARGETS];
|
||||
|
||||
ULONG ulReserved[1]; // 16 byte alignment
|
||||
|
||||
} CALIF_CAL_TARGET, *PCALIF_CAL_TARGET;
|
||||
|
||||
|
||||
|
||||
|
||||
#define CALIF_DEV_CAP_CAPABLE 0x00000001
|
||||
#define CALIF_DEV_CAP_ENABLE 0x00000002
|
||||
#define CALIF_DEV_CAP_PRIMARY 0x80000000
|
||||
|
||||
typedef struct _CALIF_DEV_INFO
|
||||
{
|
||||
ULONG ulIndex;
|
||||
|
||||
ULONG ulCaps; // CALIF_DEV_CAP_XXX
|
||||
|
||||
ULONG ulFBSize;
|
||||
LONGLONG llFBSharedSize;
|
||||
|
||||
UCHAR ucDevicePath[MAX_REGISTRY_PATH];
|
||||
|
||||
ULONG ulReserved[2];
|
||||
|
||||
} CALIF_DEV_INFO, *PCALIF_DEV_INFO;
|
||||
|
||||
|
||||
|
||||
// Output structure
|
||||
typedef struct _CALIF_CAL_STATUS
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
ULONG ulCurrentIndex;
|
||||
ULONG ulAdapterCount;
|
||||
|
||||
LONGLONG llSharedCacheableSize;
|
||||
LONGLONG llSharedUSWCSize;
|
||||
|
||||
ULONG ulLinkCount;
|
||||
ULONG ulLinkAdaper[MAX_CAL_TARGETS];
|
||||
|
||||
BOOL bP2PCap[MAX_CAL_DEVICE][MAX_CAL_DEVICE];
|
||||
|
||||
CALIF_DEV_INFO devInfo[MAX_CAL_DEVICE];
|
||||
|
||||
ULONG ulReserved[3];
|
||||
|
||||
} CALIF_CAL_STATUS, *PCALIF_CAL_STATUS;
|
||||
|
||||
|
||||
|
||||
// Output structure
|
||||
typedef struct _CALIF_VERSION
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
UINT uMajor; // Major version
|
||||
UINT uMinor; // Minor version
|
||||
|
||||
} CALIF_VERSION, *PCALIF_VERSION;
|
||||
|
||||
|
||||
|
||||
// Surface heap choice
|
||||
typedef enum _CALIF_SURF_HEAP
|
||||
{
|
||||
CALIF_SURF_HEAP_UNKNOWN = 0, // VCAM real mode or dummy surf
|
||||
CALIF_SURF_HEAP_LOCAL = 1, // Local Visible + Local Invisible
|
||||
CALIF_SURF_HEAP_LOCALIF_VISIBLE = 2,
|
||||
CALIF_SURF_HEAP_USWC = 3,
|
||||
CALIF_SURF_HEAP_CACHEABLE = 4,
|
||||
CALIF_SURF_HEAP_SHARED_USWC = 5,
|
||||
CALIF_SURF_HEAP_SHARED_CACHEABLE = 6,
|
||||
|
||||
CALIF_SURF_HEAP_INVALID = 0xFFFFFFFF,
|
||||
} CALIF_SURF_HEAP;
|
||||
|
||||
|
||||
// Surface flag
|
||||
#define CALIF_NEXT_SURF_FLAG_DUMMY 0x80000000
|
||||
#define CALIF_NEXT_SURF_FLAG_LINEAR 0x40000000
|
||||
#define CALIF_NEXT_SURF_FLAG_ARENA 0x20000000
|
||||
|
||||
// Input structure
|
||||
typedef struct _CALIF_NEXT_SURF_INFO
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
// to match it later at surface creation time
|
||||
UINT uWidth;
|
||||
UINT uHeight;
|
||||
D3DFORMAT d3dFormat;
|
||||
ULONG_PTR lpProcessID;
|
||||
|
||||
// info
|
||||
CALIF_SURF_HEAP uHeap;
|
||||
UINT uFlags;
|
||||
|
||||
#if _WIN64
|
||||
ULONG ulReserved[3];
|
||||
#endif
|
||||
|
||||
} CALIF_NEXT_SURF_INFO, *PCALIF_NEXT_SURF_INFO;
|
||||
|
||||
|
||||
|
||||
// Output structure
|
||||
typedef struct _CALIF_SURF_INFO
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
ULONG ulDeviceIndex; // current device id
|
||||
ULONG_PTR lpSurfHandle; // VCAM handle if VCAM is on
|
||||
LARGE_INTEGER gpuDevAddr; // mc address of the surface
|
||||
LONGLONG llHeapOffset; // offset from the beginning of the heap
|
||||
UINT uMemSize; // total memory size
|
||||
CALIF_SURF_HEAP uHeap; // memory pool
|
||||
UINT uGranularity; // minimum RT aligment
|
||||
UINT uBitsPerPixel; // bits per pixel
|
||||
UINT uActualWidth; // padded width pixel pitch
|
||||
UINT uActualHeight; // padded height pitch
|
||||
UINT uPitch; // padded width byte pitch
|
||||
|
||||
UINT uTile; // Tiling of surface
|
||||
UINT uTileSwizzle; // Tile swizzle of surface
|
||||
|
||||
#if !_WIN64
|
||||
ULONG ulReserved[1];
|
||||
#endif
|
||||
|
||||
} CALIF_SURF_INFO, *PCALIF_SURF_INFO;
|
||||
|
||||
|
||||
|
||||
// Input structure
|
||||
typedef struct _CALIF_ALIAS_SURF_INFO
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
ULONG ulDeviceIndex; // device id we want to alias to
|
||||
ULONG_PTR lpSurfHandle;
|
||||
LONGLONG llHeapOffset; // offset from the beginning of the heap
|
||||
UINT uMemSize; // total memory size
|
||||
CALIF_SURF_HEAP uHeap; // memory pool
|
||||
UINT uGranularity; // minimum RT aligment
|
||||
UINT uBitsPerPixel; // bits per pixel
|
||||
UINT uActualWidth; // padded width pixel pitch
|
||||
UINT uActualHeight; // padded height pitch
|
||||
UINT uPitch; // padded width byte pitch
|
||||
|
||||
#if _WIN64
|
||||
ULONG ulReserved[3];
|
||||
#endif
|
||||
|
||||
} CALIF_ALIAS_SURF_INFO, *PCALIF_ALIAS_SURF_INFO;
|
||||
|
||||
|
||||
|
||||
// Output structure
|
||||
typedef struct _CALIF_RENDER_STATUS
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulFlags;
|
||||
|
||||
BOOL bSurfBusy;
|
||||
|
||||
ULONG ulReserved[1];
|
||||
|
||||
} CALIF_RENDER_STATUS, *PCALIF_RENDER_STATUS;
|
||||
|
||||
|
||||
|
||||
// Commands for StretchBlt backdoor
|
||||
typedef enum _CALIF_SBLT_CMD
|
||||
{
|
||||
CALIF_SBLT_CMD_SURF_MARK_HELPER = 0x2200,
|
||||
CALIF_SBLT_CMD_SURF_GET_SURF_INFO = 0x2400,
|
||||
CALIF_SBLT_CMD_SURF_ALIAS = 0x2600,
|
||||
CALIF_SBLT_CMD_SEMAPHORE_WAIT = 0x4200,
|
||||
CALIF_SBLT_CMD_SEMAPHORE_SIGNAL = 0x4400,
|
||||
CALIF_SBLT_CMD_OUTPUT_CACHE_FLUSH = 0x4600,
|
||||
CALIF_SBLT_CMD_INPUT_CACHE_INVALIDATE = 0x6200,
|
||||
CALIF_SBLT_CMD_GET_RENDER_STATUS = 0x6400,
|
||||
CALIF_SBLT_CMD_PIN_SURF = 0x6600,
|
||||
CALIF_SBLT_CMD_INVALID = 0xFFFF,
|
||||
|
||||
} CALIF_SBLT_CMD;
|
||||
|
||||
|
||||
#define CALIF_SBLT_CMD_RECT_MASK__LEFT 0x000F
|
||||
#define CALIF_SBLT_CMD_RECT_MASK__TOP 0x00F0
|
||||
#define CALIF_SBLT_CMD_RECT_MASK__RIGHT 0x0F00
|
||||
#define CALIF_SBLT_CMD_RECT_MASK__BOTTOM 0xF000
|
||||
|
||||
#define CALIF_SBLT_CMD_RECT_SHIFT__LEFT 0
|
||||
#define CALIF_SBLT_CMD_RECT_SHIFT__TOP 4
|
||||
#define CALIF_SBLT_CMD_RECT_SHIFT__RIGHT 8
|
||||
#define CALIF_SBLT_CMD_RECT_SHIFT__BOTTOM 12
|
||||
|
||||
#endif//__CALIF_H__
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
* Trade secret of ATI Technologies, Inc.
|
||||
* Copyright 2000, ATI Technologies, Inc., (unpublished)
|
||||
*
|
||||
* All rights reserved. This notice is intended as a precaution against
|
||||
* inadvertent publication and does not imply publication or any waiver
|
||||
* of confidentiality. The year included in the foregoing notice is the
|
||||
* year of creation of the work.
|
||||
*
|
||||
*
|
||||
****************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef __D3DSHADERDEFS_H__
|
||||
#define __D3DSHADERDEFS_H__
|
||||
|
||||
#define D3DSI_OPCODE_PARAM (1 << 31)
|
||||
|
||||
#define D3DSI_GETCOMMENTSIZE(token) (((token) & D3DSI_COMMENTSIZE_MASK) >> \
|
||||
D3DSI_COMMENTSIZE_SHIFT)
|
||||
|
||||
#define D3DSI_GETDSTSHIFT(token) (((token) & D3DSP_DSTSHIFT_MASK) >> D3DSP_DSTSHIFT_SHIFT)
|
||||
|
||||
// D3D uses 2 swizzle bits per component. Define them since they are not
|
||||
// available in d3d header files.
|
||||
#define D3DSP_SWIZZLE_BITS_PER_COMP 2
|
||||
#define D3DSP_SWIZZLE_XYZW_MASK 0x3
|
||||
|
||||
// DST related: Parameter definition writemask shifts - missing from D3D header
|
||||
#define D3DSP_WRITEMASK_SHIFT 16
|
||||
#define D3DSP_WRITEMASK_ASHIFT 19
|
||||
|
||||
// DX9 Ref uses 7. But if only upto _X8 & _D8 are supported, the mask should be 3
|
||||
#define D3DSP_D3D_DSTSHIFT_MASK 3
|
||||
|
||||
#define D3DSP_SHADER_TYPE_MASK 0xFFFF0000
|
||||
#define D3DSP_PS_TYPE 0xFFFF0000
|
||||
#define D3DSP_VS_TYPE 0xFFFE0000
|
||||
|
||||
// This is necessary to avoid a duplicate definition of these functions
|
||||
// in C++ source files that use this header. These functions are already
|
||||
// defined in d3dhal.h inside a "#ifdef __cplusplus" block.
|
||||
#ifndef __cplusplus
|
||||
|
||||
// This gets regtype, and also maps D3DSPR_CONSTn to D3DSPR_CONST
|
||||
// (for easier parsing)
|
||||
ATI_INLINE DWORD D3DSI_GETREGTYPE_RESOLVING_CONSTANTS(DWORD token)
|
||||
{
|
||||
DWORD RegType = D3DSI_GETREGTYPE(token);
|
||||
switch (RegType)
|
||||
{
|
||||
case D3DSPR_CONST4:
|
||||
case D3DSPR_CONST3:
|
||||
case D3DSPR_CONST2:
|
||||
return D3DSPR_CONST;
|
||||
default:
|
||||
return RegType;
|
||||
}
|
||||
}
|
||||
|
||||
// The inline function below retrieves register number for an opcode,
|
||||
// taking into account that: if the type is a
|
||||
// D3DSPR_CONSTn, the register number needs to be remapped.
|
||||
//
|
||||
// D3DSPR_CONST is for c0-c2047
|
||||
// D3DSPR_CONST2 is for c2048-c4095
|
||||
// D3DSPR_CONST3 is for c4096-c6143
|
||||
// D3DSPR_CONST4 is for c6144-c8191
|
||||
//
|
||||
// For example if the instruction token specifies type D3DSPR_CONST4, reg# 3,
|
||||
// the register number retrieved is 6147.
|
||||
// For other register types, the register number is just returned unchanged.
|
||||
ATI_INLINE DWORD D3DSI_GETREGNUM_RESOLVING_CONSTANTS(DWORD token)
|
||||
{
|
||||
DWORD RegType = D3DSI_GETREGTYPE(token);
|
||||
DWORD RegNum = D3DSI_GETREGNUM(token);
|
||||
|
||||
switch(RegType)
|
||||
{
|
||||
case D3DSPR_CONST4:
|
||||
return RegNum + 6144;
|
||||
case D3DSPR_CONST3:
|
||||
return RegNum + 4096;
|
||||
case D3DSPR_CONST2:
|
||||
return RegNum + 2048;
|
||||
default:
|
||||
return RegNum;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#define PSTR_MAX_NUMSRCPARAMS 6
|
||||
#define PSTR_NUM_COMPONENTS_IN_REGISTER 4
|
||||
|
||||
#endif // __D3DSHADERDEFS_H__
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Workfile: fourcc.h
|
||||
//
|
||||
// Description: FourCC definitions
|
||||
//
|
||||
// Trade secret of ATI Technologies, Inc.
|
||||
// Copyright 1999, ATI Technologies, Inc., (unpublished)
|
||||
//
|
||||
// All rights reserved. This notice is intended as a precaution against
|
||||
// inadvertent publication and does not imply publication or any waiver
|
||||
// of confidentiality. The year included in the foregoing notice is the
|
||||
// year of creation of the work.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _FOURCC_H_
|
||||
#define _FOURCC_H_
|
||||
|
||||
//#include "atidxinc.h"
|
||||
|
||||
#define FOURCC_YUY2 MAKEFOURCC('Y','U','Y','2')
|
||||
#define FOURCC_UYVY MAKEFOURCC('U','Y','V','Y')
|
||||
#define FOURCC_YV12 MAKEFOURCC('Y','V','1','2')
|
||||
#define FOURCC_YUV12 FOURCC_YV12
|
||||
#define FOURCC_YVU9 MAKEFOURCC('Y','V','U','9')
|
||||
#define FOURCC_IF09 MAKEFOURCC('I','F','0','9')
|
||||
#define FOURCC_IMC4 MAKEFOURCC('I','M','C','4')
|
||||
#define FOURCC_IYUV MAKEFOURCC('I','Y','U','V')
|
||||
#define FOURCC_NV11 MAKEFOURCC('N','V','1','1')
|
||||
#define FOURCC_NV12 MAKEFOURCC('N','V','1','2')
|
||||
#define FOURCC_NV21 MAKEFOURCC('N','V','2','1')
|
||||
|
||||
//Microsoft specific format for WebTV
|
||||
#define FOURCC_VBID MAKEFOURCC('V','B','I','D')
|
||||
|
||||
#define FOURCC_MCAM MAKEFOURCC('M','C','A','M')
|
||||
#define FOURCC_MC12 MAKEFOURCC('M','C','1','2')
|
||||
#define FOURCC_MCR4 MAKEFOURCC('M','C','R','4')
|
||||
#define FOURCC_M2IA MAKEFOURCC('M','2','I','A')
|
||||
#define FOURCC_M2AM MAKEFOURCC('M','2','A','M')
|
||||
#define FOURCC_M2R4 MAKEFOURCC('M','2','R','4')
|
||||
#define FOURCC_AYUV MAKEFOURCC('A','Y','U','V')
|
||||
#define FOURCC_AI44 MAKEFOURCC('A','I','4','4')
|
||||
#define FOURCC_XENC MAKEFOURCC('X','E','N','C')
|
||||
|
||||
// OpenGL Surfaces
|
||||
#define FOURCC_OGLZ MAKEFOURCC('O','G','L','Z')
|
||||
#define FOURCC_OGNZ MAKEFOURCC('O','G','N','Z')
|
||||
#define FOURCC_OGLS MAKEFOURCC('O','G','L','S')
|
||||
#define FOURCC_OGNS MAKEFOURCC('O','G','N','S')
|
||||
#define FOURCC_OGLT MAKEFOURCC('O','G','L','T')
|
||||
#define FOURCC_OGNT MAKEFOURCC('O','G','N','T')
|
||||
#define FOURCC_OGLB MAKEFOURCC('O','G','L','B')
|
||||
|
||||
#define FOURCC_DDES MAKEFOURCC('D','D','E','S')
|
||||
#define FOURCC_PBSM MAKEFOURCC('P','B','S','M')
|
||||
|
||||
#define FOURCC_ATI1 MAKEFOURCC('A','T','I','1')
|
||||
#define FOURCC_ATI2 MAKEFOURCC('A','T','I','2')
|
||||
|
||||
// Alias of ARGB-8888 for special MM app. to store security content
|
||||
#define FOURCC_SORT MAKEFOURCC('S','O','R','T')
|
||||
// Alias of YUY2 for special MM app. to store security content
|
||||
#define FOURCC_SYV2 MAKEFOURCC('S','Y','V','2')
|
||||
// Communication surface for special MM app. to enable security content playback
|
||||
#define FOURCC_EAPI MAKEFOURCC('E','A','P','I')
|
||||
|
||||
// Communication surface
|
||||
#define FOURCC_ATIC MAKEFOURCC('A','T','I','C')
|
||||
|
||||
// Fake format for exposing DX9c geometry instancing
|
||||
#define FOURCC_INST MAKEFOURCC('I','N','S','T')
|
||||
|
||||
// Fake format for exposing R2VB support
|
||||
// must match FOURCC_R2VB in d3d/atir2vb.h
|
||||
#define FOURCC_R2VB MAKEFOURCC('R','2','V','B')
|
||||
|
||||
// Depth Stencil Texture formats.
|
||||
#define FOURCC_DF16 MAKEFOURCC('D','F','1','6')
|
||||
#define FOURCC_DF24 MAKEFOURCC('D','F','2','4')
|
||||
|
||||
// FP_11_11_10 format - used internally for optimization
|
||||
#define FOURCC_FP11 MAKEFOURCC('F','P','1','1')
|
||||
|
||||
|
||||
// Fetch4:
|
||||
// GET4 is used both as fake format for exposing Fetch4 and as enable value.
|
||||
// GET1 is used only as disable value.
|
||||
#define FOURCC_GET4 MAKEFOURCC('G','E','T','4')
|
||||
#define FOURCC_GET1 MAKEFOURCC('G','E','T','1')
|
||||
|
||||
// ATI Compute Abstraction Layer (CAL)
|
||||
// U8X1 stands for unsigned 8 bits by 1 component
|
||||
// S6X4 stands for signed 16 bits by 4 components
|
||||
#define FOURCC_ATIP MAKEFOURCC('A','T','I','P')
|
||||
#define FOURCC_U8X1 MAKEFOURCC('U','8','X','1')
|
||||
#define FOURCC_S8X1 MAKEFOURCC('S','8','X','1')
|
||||
#define FOURCC_U8X2 MAKEFOURCC('U','8','X','2')
|
||||
#define FOURCC_S8X2 MAKEFOURCC('S','8','X','2')
|
||||
#define FOURCC_S8X4 MAKEFOURCC('S','8','X','4')
|
||||
#define FOURCC_U6X1 MAKEFOURCC('U','6','X','1')
|
||||
#define FOURCC_S6X1 MAKEFOURCC('S','6','X','1')
|
||||
#define FOURCC_S6X2 MAKEFOURCC('S','6','X','2')
|
||||
#define FOURCC_S6X4 MAKEFOURCC('S','6','X','4')
|
||||
|
||||
// ATI semaphore, currently used by CAL
|
||||
#define FOURCC_SEMA MAKEFOURCC('S','E','M','A')
|
||||
|
||||
#endif // _FOURCC_H_
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
Promotions directory contains functionality from other staging branches copied
|
||||
(promoted) into the CAL tree.
|
||||
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
#ifndef __DXXOPENCLINTEROPEXT_H__
|
||||
#define __DXXOPENCLINTEROPEXT_H__
|
||||
|
||||
// Abstract extension interface class
|
||||
// Each extension interface (e.g. OpenCL Interop extension) will derive from this class
|
||||
class IAmdDxExtInterface
|
||||
{
|
||||
public:
|
||||
virtual unsigned int AddRef(void) = 0;
|
||||
virtual unsigned int Release(void) = 0;
|
||||
|
||||
protected:
|
||||
IAmdDxExtInterface() {};
|
||||
virtual ~IAmdDxExtInterface() = 0 {};
|
||||
};
|
||||
|
||||
// forward declaration for d3d specific interfaces
|
||||
interface ID3D10Device;
|
||||
interface ID3D11Device;
|
||||
interface IDirect3DDevice9Ex;
|
||||
interface ID3D10Resource;
|
||||
interface ID3D11Resource;
|
||||
interface IDirect3DSurface9;
|
||||
|
||||
// forward declaration of extended primitive topology enumeration
|
||||
enum AmdDxExtPrimitiveTopology;
|
||||
|
||||
// Extension version information
|
||||
struct AmdDxExtVersion
|
||||
{
|
||||
unsigned int majorVersion;
|
||||
unsigned int minorVersion;
|
||||
};
|
||||
|
||||
// This class serves as the main extension interface.
|
||||
// AmdDxExtCreate returns a pointer to an instantiation of this interface.
|
||||
// This object is used to retrieve extension version information
|
||||
// and to get specific extension interfaces desired.
|
||||
class IAmdDxExt : public IAmdDxExtInterface
|
||||
{
|
||||
public:
|
||||
virtual HRESULT GetVersion(AmdDxExtVersion* pExtVer) = 0;
|
||||
virtual IAmdDxExtInterface* GetExtInterface(unsigned int iface) = 0;
|
||||
|
||||
// General extensions
|
||||
virtual HRESULT IaSetPrimitiveTopology(unsigned int topology) = 0;
|
||||
virtual HRESULT IaGetPrimitiveTopology(AmdDxExtPrimitiveTopology* pExtTopology) = 0;
|
||||
virtual HRESULT SetSingleSampleRead(ID3D10Resource* pResource, BOOL singleSample) = 0;
|
||||
virtual HRESULT SetSingleSampleRead11(ID3D11Resource* pResource, BOOL singleSample) = 0;
|
||||
virtual HRESULT SetSingleSampleRead9(IDirect3DSurface9* pResource, BOOL singleSample) = 0;
|
||||
|
||||
protected:
|
||||
IAmdDxExt() {};
|
||||
virtual ~IAmdDxExt() = 0 {};
|
||||
};
|
||||
|
||||
// OpenCL Interop extension ID passed to IAmdDxExt::GetExtInterface()
|
||||
const unsigned int AmdDxExtCLInteropID = 7;
|
||||
|
||||
// Abstract OpenCL Interop extension interface class
|
||||
class IAmdDxExtCLInterop : public IAmdDxExtInterface
|
||||
{
|
||||
public:
|
||||
virtual HRESULT QueryInteropGpuMask(UINT* gpuIdBitmask) = 0;
|
||||
|
||||
virtual HRESULT CLAcquireResource(ID3D10Resource* pResource, UINT* gpuIdBitmask) = 0;
|
||||
virtual HRESULT CLReleaseResource(ID3D10Resource* pResource, UINT* gpuIdBitmask) = 0;
|
||||
|
||||
virtual HRESULT CLAcquireResource11(ID3D11Resource* pResource, UINT* gpuIdBitmask) = 0;
|
||||
virtual HRESULT CLReleaseResource11(ID3D11Resource* pResource, UINT* gpuIdBitmask) = 0;
|
||||
|
||||
virtual HRESULT CLAcquireResource9(IDirect3DSurface9* pResource, UINT* gpuIdBitmask) = 0;
|
||||
virtual HRESULT CLReleaseResource9(IDirect3DSurface9* pResource, UINT* gpuIdBitmask) = 0;
|
||||
};
|
||||
|
||||
// Use GetProcAddress, etc. to retrieve exported functions
|
||||
// The associated typedef provides a convenient way to define the function pointer
|
||||
HRESULT __cdecl AmdDxExtCreate(ID3D10Device* pDevice, IAmdDxExt** ppExt);
|
||||
typedef HRESULT (__cdecl *PFNAmdDxExtCreate)(ID3D10Device* pDevice, IAmdDxExt** ppExt);
|
||||
|
||||
HRESULT __cdecl AmdDxExtCreate11(ID3D11Device* pDevice, IAmdDxExt** ppExt);
|
||||
typedef HRESULT (__cdecl *PFNAmdDxExtCreate11)(ID3D11Device* pDevice, IAmdDxExt** ppExt);
|
||||
|
||||
HRESULT __cdecl AmdDxExtCreate9(IDirect3DDevice9Ex* pDevice, IAmdDxExt** ppExt);
|
||||
typedef HRESULT (__cdecl *PFNAmdDxExtCreate9)(IDirect3DDevice9Ex* pDevice, IAmdDxExt** ppExt);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
#include "EventQueue.h"
|
||||
#include "query/QueryObject.h"
|
||||
#include "gsl_ctx.h"
|
||||
|
||||
EventQueue::EventQueue()
|
||||
{
|
||||
m_cs = NULL;
|
||||
m_queueSize = c_staticQueueSize;
|
||||
|
||||
memset(m_queries,0,sizeof(m_queries));
|
||||
memset(m_flushed,0,sizeof(m_flushed));
|
||||
|
||||
m_latestRetired = 0;
|
||||
m_headId = m_queueSize - 1 ;
|
||||
m_tail = 0;
|
||||
}
|
||||
|
||||
EventQueue::~EventQueue()
|
||||
{
|
||||
for (unsigned int i = 0; i < c_staticQueueSize; i++)
|
||||
{
|
||||
assert(m_queries[i] == 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
EventQueue::open(gsCtx* cs, gslQueryTarget target, EQManagerConfig config, uint32 engineMask)
|
||||
{
|
||||
assert((config == EQManager_HIGH) || (config == EQManager_LOW));
|
||||
setSlotCount((int) config);
|
||||
assert((GpuEvent::InvalidID+1) % m_queueSize == 0);
|
||||
|
||||
m_cs = cs;
|
||||
|
||||
m_headId = m_queueSize - 1 ;
|
||||
m_tail = 0;
|
||||
m_latestRetired = 0;
|
||||
m_target = target;
|
||||
m_engineMask = engineMask;
|
||||
|
||||
for (unsigned int i = 0; i < m_queueSize; i++)
|
||||
{
|
||||
m_queries[i] = cs->createQuery(target);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
EventQueue::close()
|
||||
{
|
||||
if (!m_cs) // the queue is unintialized.
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < m_queueSize; i++)
|
||||
{
|
||||
m_cs->destroyQuery(m_queries[i]);
|
||||
}
|
||||
memset(m_queries, 0, sizeof(m_queries));
|
||||
memset(m_flushed, 0, sizeof(m_flushed));
|
||||
m_latestRetired = 0;
|
||||
m_headId = m_queueSize - 1 ;
|
||||
m_tail = 0;
|
||||
m_cs = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
EventQueue::begin()
|
||||
{
|
||||
const CALuint slot = m_headId % m_queueSize;
|
||||
gslErrorCode ec = m_queries[slot]->BeginQuery(m_cs, m_target, 0, m_engineMask);
|
||||
assert(ec == GSL_NO_ERROR);
|
||||
|
||||
m_flushed[slot] = false; // we've started a query, but it hasn't been checked yet...
|
||||
}
|
||||
|
||||
uint32
|
||||
EventQueue::end()
|
||||
{
|
||||
uint32 ret = m_headId;
|
||||
const uint32 slot = m_headId % m_queueSize;
|
||||
|
||||
m_queries[slot]->EndQuery(m_cs, 0);
|
||||
|
||||
m_headId++;
|
||||
m_tail++;
|
||||
|
||||
if (GpuEvent::InvalidID == m_headId)
|
||||
{
|
||||
// Flush on an event ID wrap around or when the Queue is going to wrap in
|
||||
flush();
|
||||
//roll numbers back to the beginning
|
||||
m_latestRetired = 0;
|
||||
m_headId = m_headId % m_queueSize;
|
||||
m_tail = m_tail % m_queueSize;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
EventQueue::isDone(uint32 event)
|
||||
{
|
||||
assert((event < GpuEvent::InvalidID) && "illegal event handle");
|
||||
// if the event is older the the last known retired event we
|
||||
// do not need to process it.
|
||||
if (event <= m_latestRetired)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the event is older than the oldest event handle we have
|
||||
// we synchronize with the oldest event.
|
||||
if (event < m_tail)
|
||||
{
|
||||
return waitForEvent(m_tail, CAL_WAIT_LOW_CPU_UTILIZATION);
|
||||
}
|
||||
|
||||
//
|
||||
// If we've never called flush on the query object, go ahead flush the first time to ensure
|
||||
// we never infinite loop
|
||||
//
|
||||
const uint32 slot = event % m_queueSize;
|
||||
if (!m_flushed[slot])
|
||||
{
|
||||
flush();
|
||||
}
|
||||
|
||||
//
|
||||
// Since we're in between, we actually have to check to see if things are truely done
|
||||
//
|
||||
bool retVal = m_queries[slot]->IsResultAvailable(m_cs);
|
||||
|
||||
// cache the most recently retired event
|
||||
if (retVal && (event < m_headId) && (event > m_latestRetired))
|
||||
{
|
||||
m_latestRetired = event;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool
|
||||
EventQueue::waitForEvent(uint32 event, uint32 waitType)
|
||||
{
|
||||
// if we already retired a younger event we don't to process current events
|
||||
if (event <= m_latestRetired)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the event is older than the oldest event handle we have
|
||||
// we synchronize with the oldest event
|
||||
if (event < m_tail)
|
||||
{
|
||||
event = m_tail;
|
||||
}
|
||||
|
||||
//
|
||||
// If we've never called flush on the query object, go ahead flush the first time to ensure
|
||||
// we never infinite loop
|
||||
//
|
||||
const uint32 slot = event % m_queueSize;
|
||||
if (!m_flushed[slot])
|
||||
{
|
||||
flush();
|
||||
}
|
||||
uint64 param;
|
||||
m_queries[slot]->GetResult(m_cs, ¶m, waitType);
|
||||
|
||||
// cache the most recently retired event
|
||||
if ((event < m_headId) && (event > m_latestRetired))
|
||||
{
|
||||
m_latestRetired = event;
|
||||
}
|
||||
|
||||
return (param != 0);
|
||||
}
|
||||
|
||||
bool
|
||||
EventQueue::flush()
|
||||
{
|
||||
m_cs->Flush(false, m_engineMask);
|
||||
memset(m_flushed, 1, sizeof(m_flushed));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EventQueue::setSlotCount(uint32 slotCount)
|
||||
{
|
||||
if (slotCount < c_staticQueueSize)
|
||||
{
|
||||
m_queueSize = slotCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_queueSize = c_staticQueueSize;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef __EventQueue_h__
|
||||
#define __EventQueue_h__
|
||||
|
||||
#include "cal.h"
|
||||
#include "backend.h"
|
||||
#include "atitypes.h"
|
||||
#include "gsl_types.h"
|
||||
#include "gsl_config.h"
|
||||
|
||||
//#define USE_3D_SYNC 1
|
||||
|
||||
namespace gsl
|
||||
{
|
||||
class gsCtx;
|
||||
};
|
||||
|
||||
enum EQManagerConfig
|
||||
{
|
||||
EQManager_HIGH = 512,
|
||||
EQManager_LOW = 32
|
||||
};
|
||||
|
||||
class EventQueue {
|
||||
public:
|
||||
static const unsigned int c_staticQueueSize = EQManager_HIGH;
|
||||
EventQueue();
|
||||
~EventQueue();
|
||||
|
||||
bool open(gsl::gsCtx* cs, gslQueryTarget target, EQManagerConfig config, uint32 engineMask = GSL_ENGINEMASK_ALL_BUT_UVD_VCE);
|
||||
void close();
|
||||
|
||||
void begin();
|
||||
uint32 end();
|
||||
bool isDone(uint32 event);
|
||||
bool waitForEvent(uint32 event, uint32 waitType);
|
||||
bool flush();
|
||||
|
||||
private:
|
||||
|
||||
gsl::gsCtx* m_cs;
|
||||
|
||||
uint32 m_queueSize;
|
||||
gslQueryTarget m_target;
|
||||
uint32 m_engineMask; // EngineMask for this Query
|
||||
uint32 m_tail; //represents the oldest event we have
|
||||
uint32 m_headId;
|
||||
uint32 m_latestRetired; //!< most recentyl retired event.
|
||||
gslQueryObject m_queries[c_staticQueueSize];
|
||||
bool m_flushed[c_staticQueueSize];
|
||||
///////////////////////
|
||||
// private functions //
|
||||
///////////////////////
|
||||
void setSlotCount(uint32 slotCount);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user