Add GrMtlTexture classes

Adds support for basic Texture creation.

Bug: skia:
Change-Id: I9a3f15bef1c88054c19e952e231cad94ad69f296
Reviewed-on: https://skia-review.googlesource.com/30781
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Greg Daniel 2017-08-04 09:34:44 -04:00 committed by Skia Commit-Bot
parent 21c3fb94de
commit 4a081e2475
7 changed files with 218 additions and 4 deletions

View File

@ -585,6 +585,8 @@ skia_metal_sources = [
"$_src/gpu/mtl/GrMtlCaps.mm",
"$_src/gpu/mtl/GrMtlGpu.h",
"$_src/gpu/mtl/GrMtlGpu.mm",
"$_src/gpu/mtl/GrMtlTexture.mm",
"$_src/gpu/mtl/GrMtlTexture.h",
"$_src/gpu/mtl/GrMtlTrampoline.h",
"$_src/gpu/mtl/GrMtlTrampoline.mm",
"$_src/gpu/mtl/GrMtlUtil.h",

View File

@ -29,6 +29,8 @@ public:
const GrMtlCaps& mtlCaps() const { return *fMtlCaps.get(); }
id<MTLDevice> device() const { return fDevice; }
bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override { return false; }
@ -72,9 +74,7 @@ private:
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
const GrMipLevel texels[], int mipLevelCount) override {
return nullptr;
}
const GrMipLevel texels[], int mipLevelCount) override;
sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&,
GrSurfaceOrigin,

View File

@ -7,6 +7,8 @@
#include "GrMtlGpu.h"
#include "GrMtlTexture.h"
#if !__has_feature(objc_arc)
#error This file must be compiled with Arc. Use -fobjc-arc flag
#endif
@ -103,3 +105,42 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
// Unused queue warning fix
SkDebugf("ptr to queue: %p\n", fQueue);
}
sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
const GrMipLevel texels[], int mipLevelCount) {
int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
if (!fMtlCaps->isConfigTexturable(desc.fConfig)) {
return nullptr;
}
bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
if (renderTarget) {
// Current we don't have render target support
return nullptr;
}
sk_sp<GrMtlTexture> tex;
if (renderTarget) {
// Enable once we have render target support
#if 0
tex = GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted,
desc, mipLevels);
#endif
} else {
tex = GrMtlTexture::CreateNewTexture(this, budgeted, desc, mipLevels);
}
if (!tex) {
return nullptr;
}
if (mipLevelCount) {
// Perform initial data upload here
}
if (desc.fFlags & kPerformInitialClear_GrSurfaceFlag) {
// Do initial clear of the texture
}
return tex;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrMtlTexture_DEFINED
#define GrMtlTexture_DEFINED
#include "GrTexture.h"
#import <Metal/Metal.h>
class GrMtlGpu;
class GrMtlTexture : public GrTexture {
public:
static sk_sp<GrMtlTexture> CreateNewTexture(GrMtlGpu*, SkBudgeted budgeted,
const GrSurfaceDesc&, int mipLevels);
static sk_sp<GrMtlTexture> MakeWrappedTexture(GrMtlGpu*, const GrSurfaceDesc&,
GrWrapOwnership);
~GrMtlTexture() override;
id<MTLTexture> mtlTexture() const { return fTexture; }
GrBackendObject getTextureHandle() const override;
void textureParamsModified() override {}
bool reallocForMipmap(GrMtlGpu* gpu, uint32_t mipLevels);
void setRelease(GrTexture::ReleaseProc proc, GrTexture::ReleaseCtx ctx) override {
// Since all MTLResources are inherently ref counted, we can call the Release proc when we
// delete the GrMtlTexture without worry of the MTLTexture getting deleted before it is done
// on the GPU.
fReleaseProc = proc;
fReleaseCtx = ctx;
}
protected:
GrMtlTexture(GrMtlGpu*, const GrSurfaceDesc&);
GrMtlGpu* getMtlGpu() const;
void onAbandon() override {
fTexture = nil;
}
void onRelease() override {
fTexture = nil;
}
private:
enum Wrapped { kWrapped };
GrMtlTexture(GrMtlGpu*, SkBudgeted, const GrSurfaceDesc&, id<MTLTexture>, bool isMipMapped);
// GrMtlTexture(GrMtlGpu*, Wrapped, const GrSurfaceDesc&, GrMtlImage::Wrapped wrapped);
id<MTLTexture> fTexture;
ReleaseProc fReleaseProc = nullptr;
ReleaseCtx fReleaseCtx = nullptr;
typedef GrTexture INHERITED;
};
#endif

View File

@ -0,0 +1,78 @@
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrMtlTexture.h"
#include "GrMtlGpu.h"
#include "GrMtlUtil.h"
#include "GrTexturePriv.h"
sk_sp<GrMtlTexture> GrMtlTexture::CreateNewTexture(GrMtlGpu* gpu, SkBudgeted budgeted,
const GrSurfaceDesc& desc, int mipLevels) {
MTLPixelFormat format;
if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
return nullptr;
}
MTLTextureDescriptor* descriptor = [[MTLTextureDescriptor alloc] init];
descriptor.textureType = MTLTextureType2D;
descriptor.pixelFormat = format;
descriptor.width = desc.fWidth;
descriptor.height = desc.fHeight;
descriptor.depth = 1;
descriptor.mipmapLevelCount = mipLevels;
descriptor.sampleCount = 1;
descriptor.arrayLength = 1;
// descriptor.resourceOptions This looks to be set by setting cpuCacheMode and storageModes
descriptor.cpuCacheMode = MTLCPUCacheModeWriteCombined;
// Shared is not available on MacOS. Is there a reason to want managed to allow mapping?
descriptor.storageMode = MTLStorageModePrivate;
MTLTextureUsage texUsage = MTLTextureUsageShaderRead;
if (GrMTLFormatIsSRGB(format, nullptr)) {
texUsage |= MTLTextureUsagePixelFormatView;
}
descriptor.usage = texUsage;
id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:descriptor];
return sk_sp<GrMtlTexture>(new GrMtlTexture(gpu, budgeted, desc, texture, mipLevels > 1));
}
// This method parallels GrTextureProxy::highestFilterMode
static inline GrSamplerParams::FilterMode highest_filter_mode(GrPixelConfig config) {
if (GrPixelConfigIsSint(config)) {
// We only ever want to nearest-neighbor sample signed int textures.
return GrSamplerParams::kNone_FilterMode;
}
return GrSamplerParams::kMipMap_FilterMode;
}
GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
SkBudgeted budgeted,
const GrSurfaceDesc& desc,
id<MTLTexture> texture,
bool isMipMapped)
: GrSurface(gpu, desc)
, INHERITED(gpu, desc, kTexture2DSampler_GrSLType, highest_filter_mode(desc.fConfig),
isMipMapped)
, fTexture(texture) {
}
GrMtlTexture::~GrMtlTexture() {
SkASSERT(nil == fTexture);
}
GrMtlGpu* GrMtlTexture::getMtlGpu() const {
SkASSERT(!this->wasDestroyed());
return static_cast<GrMtlGpu*>(this->getGpu());
}
GrBackendObject GrMtlTexture::getTextureHandle() const {
void* voidTex = (__bridge_retained void*)fTexture;
return (GrBackendObject)voidTex;
}

View File

@ -22,5 +22,10 @@ bool GrPixelConfigToMTLFormat(GrPixelConfig config, MTLPixelFormat* format);
*/
GrPixelConfig GrMTLFormatToPixelConfig(MTLPixelFormat format);
/**
* Returns true if the given vulkan texture format is sRGB encoded.
* Also provides the non-sRGB version, if there is one.
*/
bool GrMTLFormatIsSRGB(MTLPixelFormat format, MTLPixelFormat* linearFormat);
#endif

View File

@ -101,3 +101,23 @@ GrPixelConfig GrMTLFormatToPixelConfig(MTLPixelFormat format) {
return kUnknown_GrPixelConfig;
}
}
bool GrMTLFormatIsSRGB(MTLPixelFormat format, MTLPixelFormat* linearFormat) {
MTLPixelFormat linearFmt = format;
switch (format) {
case MTLPixelFormatRGBA8Unorm_sRGB:
linearFmt = MTLPixelFormatRGBA8Unorm;
break;
case MTLPixelFormatBGRA8Unorm_sRGB:
linearFmt = MTLPixelFormatBGRA8Unorm;
break;
default:
break;
}
if (linearFormat) {
*linearFormat = linearFmt;
}
return (linearFmt != format);
}