Merge "Make TextureView's HDR definitions the same as ColorSpace's" into udc-dev

This commit is contained in:
Alec Mouri
2023-05-02 23:22:37 +00:00
committed by Android (Google) Code Review
3 changed files with 155 additions and 35 deletions

View File

@@ -97,7 +97,6 @@ void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, flo
.inputDataspace = sourceDataspace, .inputDataspace = sourceDataspace,
.outputDataspace = destinationDataspace, .outputDataspace = destinationDataspace,
.undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType, .undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
.fakeInputDataspace = destinationDataspace,
.type = shaders::LinearEffect::SkSLType::ColorFilter}; .type = shaders::LinearEffect::SkSLType::ColorFilter};
constexpr float kMaxDisplayBrightnessNits = 1000.f; constexpr float kMaxDisplayBrightnessNits = 1000.f;
constexpr float kCurrentDisplayBrightnessNits = 500.f; constexpr float kCurrentDisplayBrightnessNits = 500.f;

View File

@@ -284,7 +284,9 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
case HAL_DATASPACE_TRANSFER_GAMMA2_8: case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084: case HAL_DATASPACE_TRANSFER_ST2084:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut); return SkColorSpace::MakeRGB({-2.0, -1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
-2392 / 128.0, 8192 / 1305.0},
gamut);
case HAL_DATASPACE_TRANSFER_SMPTE_170M: case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut); return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_UNSPECIFIED: case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -427,10 +429,10 @@ skcms_TransferFunction GetExtendedTransferFunction(float sdrHdrRatio) {
} }
// Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB // Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB
// but LinearEffect expects a decoded [0, 1] range instead to follow Rec 2100. // but LinearEffect expects to map 1.0 == 203 nits
std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() { std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() {
skcms_TransferFunction hlgFn; skcms_TransferFunction hlgFn;
if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f, 1.f / 0.17883277f, if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f, 1.f / 0.17883277f,
0.28466892f, 0.55991073f)) { 0.28466892f, 0.55991073f)) {
return std::make_optional<skcms_TransferFunction>(hlgFn); return std::make_optional<skcms_TransferFunction>(hlgFn);
} }

View File

@@ -26,39 +26,57 @@ import android.graphics.Paint;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.RenderNode; import android.graphics.RenderNode;
import android.graphics.Shader; import android.graphics.Shader;
import android.graphics.SurfaceTexture;
import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer;
import android.media.Image; import android.media.Image;
import android.media.ImageWriter; import android.media.ImageWriter;
import android.os.Bundle; import android.os.Bundle;
import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View; import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask; import java.util.concurrent.FutureTask;
@SuppressWarnings({"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callback, public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callback,
AdapterView.OnItemSelectedListener { TextureView.SurfaceTextureListener {
private static final int WIDTH = 512; private static final int WIDTH = 512;
private static final int HEIGHT = 512; private static final int HEIGHT = 512;
private ImageView mImageView; private ImageView mImageView;
private SurfaceView mSurfaceView; private SurfaceView mSurfaceView;
private TextureView mTextureView;
private HardwareBuffer mGradientBuffer; private HardwareBuffer mGradientBuffer;
private ImageWriter mImageWriter; private Map<View, ImageWriter> mImageWriters = new HashMap<>();
private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); private ColorSpace mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
private String[] mColorNames = {"sRGB", "BT2020_HLG", "BT2020_PQ"}; private String[] mColorNames = {"sRGB", "BT2020_HLG", "BT2020_PQ"};
private String mCurrentColorName = "sRGB";
private FutureTask<HardwareBuffer> authorGradientBuffer(HardwareBuffer buffer) { private int mGradientEndColor = 0xFFFFFFFF;
private int[] mGradientEndColors = {0xFFFFFFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF};
private String[] mGradientColorNames = {"Grayscale", "Red", "Green", "Blue"};
private final ExecutorService mBufferFenceExecutor = Executors.newFixedThreadPool(1);
private final ExecutorService mBufferExecutor = Executors.newFixedThreadPool(1);
private FutureTask<HardwareBuffer> authorGradientBuffer(
HardwareBuffer buffer, int gradentEndColor) {
HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer); HardwareBufferRenderer renderer = new HardwareBufferRenderer(buffer);
RenderNode node = new RenderNode("content"); RenderNode node = new RenderNode("content");
node.setPosition(0, 0, buffer.getWidth(), buffer.getHeight()); node.setPosition(0, 0, buffer.getWidth(), buffer.getHeight());
@@ -66,9 +84,10 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
Canvas canvas = node.beginRecording(); Canvas canvas = node.beginRecording();
LinearGradient gradient = new LinearGradient( LinearGradient gradient = new LinearGradient(
0, 0, buffer.getWidth(), buffer.getHeight(), 0xFF000000, 0, 0, buffer.getWidth(), buffer.getHeight(), 0xFF000000,
0xFFFFFFFF, Shader.TileMode.CLAMP); gradentEndColor, Shader.TileMode.CLAMP);
Paint paint = new Paint(); Paint paint = new Paint();
paint.setShader(gradient); paint.setShader(gradient);
paint.setDither(true);
canvas.drawRect(0f, 0f, buffer.getWidth(), buffer.getHeight(), paint); canvas.drawRect(0f, 0f, buffer.getWidth(), buffer.getHeight(), paint);
node.endRecording(); node.endRecording();
@@ -78,7 +97,7 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
FutureTask<HardwareBuffer> resolvedBuffer = new FutureTask<>(() -> buffer); FutureTask<HardwareBuffer> resolvedBuffer = new FutureTask<>(() -> buffer);
renderer.obtainRenderRequest() renderer.obtainRenderRequest()
.setColorSpace(colorSpace) .setColorSpace(colorSpace)
.draw(Executors.newSingleThreadExecutor(), result -> { .draw(mBufferFenceExecutor, result -> {
result.getFence().await(Duration.ofSeconds(3)); result.getFence().await(Duration.ofSeconds(3));
resolvedBuffer.run(); resolvedBuffer.run();
}); });
@@ -90,7 +109,7 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
WIDTH, HEIGHT, PixelFormat.RGBA_8888, 1, WIDTH, HEIGHT, PixelFormat.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT); | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT);
return authorGradientBuffer(buffer); return authorGradientBuffer(buffer, mGradientEndColor);
} }
@Override @Override
@@ -101,29 +120,70 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB); mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
ArrayAdapter<String> adapter = new ArrayAdapter<>( ArrayAdapter<String> colorSpaceAdapter = new ArrayAdapter<>(
this, android.R.layout.simple_spinner_item, mColorNames); this, android.R.layout.simple_spinner_item, mColorNames);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); colorSpaceAdapter
Spinner spinner = new Spinner(this); .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter); Spinner colorSpaceSpinner = new Spinner(this);
spinner.setOnItemSelectedListener(this); colorSpaceSpinner.setAdapter(colorSpaceAdapter);
colorSpaceSpinner.setOnItemSelectedListener(new ColorSpaceOnItemSelectedListener());
ArrayAdapter<String> gradientColorAdapter = new ArrayAdapter<>(
this, android.R.layout.simple_spinner_item, mGradientColorNames);
gradientColorAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner gradientColorSpinner = new Spinner(this);
gradientColorSpinner.setAdapter(gradientColorAdapter);
gradientColorSpinner
.setOnItemSelectedListener(new GradientColorOnItemSelectedListener());
mGradientBuffer = getGradientBuffer().get(); mGradientBuffer = getGradientBuffer().get();
LinearLayout linearLayout = new LinearLayout(this); LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setOrientation(LinearLayout.VERTICAL);
TextView imageViewText = new TextView(this);
imageViewText.setText("ImageView");
mImageView = new ImageView(this); mImageView = new ImageView(this);
TextView textureViewText = new TextView(this);
textureViewText.setText("TextureView");
mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);
TextView surfaceViewText = new TextView(this);
surfaceViewText.setText("SurfaceView");
mSurfaceView = new SurfaceView(this); mSurfaceView = new SurfaceView(this);
mSurfaceView.getHolder().addCallback(this); mSurfaceView.getHolder().addCallback(this);
linearLayout.addView(spinner, new LinearLayout.LayoutParams( LinearLayout spinnerLayout = new LinearLayout(this);
spinnerLayout.setOrientation(LinearLayout.HORIZONTAL);
spinnerLayout.addView(colorSpaceSpinner, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT)); LinearLayout.LayoutParams.WRAP_CONTENT));
spinnerLayout.addView(gradientColorSpinner, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(spinnerLayout, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(imageViewText, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mImageView, new LinearLayout.LayoutParams(WIDTH, HEIGHT)); linearLayout.addView(mImageView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
linearLayout.addView(textureViewText, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mTextureView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
linearLayout.addView(surfaceViewText, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT)); linearLayout.addView(mSurfaceView, new LinearLayout.LayoutParams(WIDTH, HEIGHT));
setContentView(linearLayout); setContentView(linearLayout);
@@ -145,16 +205,24 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
} }
private void populateBuffers() { private void populateBuffers() {
Bitmap bitmap = Bitmap.wrapHardwareBuffer( try {
mGradientBuffer, ColorSpace.get(ColorSpace.Named.SRGB)); Bitmap bitmap = Bitmap.wrapHardwareBuffer(
Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false); getGradientBuffer().get(), ColorSpace.get(ColorSpace.Named.SRGB));
copy.setColorSpace(mColorSpace); Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, false);
mImageView.setImageBitmap(copy); copy.setColorSpace(mColorSpace);
mImageView.setImageBitmap(copy);
try (Image image = mImageWriter.dequeueInputImage()) { for (ImageWriter writer : mImageWriters.values()) {
authorGradientBuffer(image.getHardwareBuffer()).get(); mBufferExecutor.execute(() -> {
image.setDataSpace(mColorSpace.getDataSpace()); try (Image image = writer.dequeueInputImage()) {
mImageWriter.queueInputImage(image); authorGradientBuffer(image.getHardwareBuffer(), mGradientEndColor).get();
image.setDataSpace(mColorSpace.getDataSpace());
writer.queueInputImage(image);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@@ -167,30 +235,81 @@ public class ColorBitmapActivity extends Activity implements SurfaceHolder.Callb
@Override @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mImageWriter = new ImageWriter.Builder(holder.getSurface()) mImageWriters.put(mSurfaceView, new ImageWriter.Builder(holder.getSurface())
.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE .setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT | HardwareBuffer.USAGE_GPU_COLOR_OUTPUT
| HardwareBuffer.USAGE_COMPOSER_OVERLAY) | HardwareBuffer.USAGE_COMPOSER_OVERLAY)
.build(); .build());
populateBuffers(); populateBuffers();
} }
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
mImageWriter.close(); if (mImageWriters.containsKey(mSurfaceView)) {
mImageWriter = null; mImageWriters.remove(mSurfaceView);
}
} }
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onSurfaceTextureAvailable(
mCurrentColorName = mColorNames[position]; @NonNull SurfaceTexture surface, int width, int height) {
mColorSpace = getFromName(mCurrentColorName); mImageWriters.put(mTextureView, new ImageWriter.Builder(new Surface(surface))
.setUsage(HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
| HardwareBuffer.USAGE_GPU_COLOR_OUTPUT)
.build());
populateBuffers(); populateBuffers();
} }
@Override @Override
public void onNothingSelected(AdapterView<?> parent) { public void onSurfaceTextureSizeChanged(
@NonNull SurfaceTexture surface, int width, int height) {
} }
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
if (mImageWriters.containsKey(mTextureView)) {
mImageWriters.remove(mTextureView);
}
return false;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
}
private final class ColorSpaceOnItemSelectedListener
implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
ColorBitmapActivity.this.mColorSpace =
getFromName(ColorBitmapActivity.this.mColorNames[position]);
ColorBitmapActivity.this.getMainExecutor()
.execute(ColorBitmapActivity.this::populateBuffers);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
private final class GradientColorOnItemSelectedListener
implements AdapterView.OnItemSelectedListener {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
ColorBitmapActivity.this.mGradientEndColor =
ColorBitmapActivity.this.mGradientEndColors[position];
ColorBitmapActivity.this.getMainExecutor()
.execute(ColorBitmapActivity.this::populateBuffers);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
} }