| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <set> |
| |
| #include <gtest/gtest.h> |
| #include <va/va.h> |
| #include <va/va_magma.h> |
| |
| static VAStatus vaCreateConfigReturn = VA_STATUS_SUCCESS; |
| static VAStatus vaCreateContextReturn = VA_STATUS_SUCCESS; |
| static VAStatus vaCreateSurfacesReturn = VA_STATUS_SUCCESS; |
| static int vaGetDisplayMagmaReturn; |
| |
| static const std::set<VASurfaceID> vaFreeSurfacesDefault = { |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, |
| 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, |
| 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; |
| static std::set<VASurfaceID> vaFreeSurfaces = vaFreeSurfacesDefault; |
| |
| void vaDefaultStubSetReturn() { |
| vaCreateConfigReturn = VA_STATUS_SUCCESS; |
| vaCreateContextReturn = VA_STATUS_SUCCESS; |
| vaCreateSurfacesReturn = VA_STATUS_SUCCESS; |
| vaFreeSurfaces = vaFreeSurfacesDefault; |
| } |
| |
| struct FakeBuffer { |
| VABufferType type{}; |
| size_t size{}; |
| std::unique_ptr<std::vector<uint8_t>> mapped_buffer; |
| std::unique_ptr<VACodedBufferSegment> coded_segment; |
| }; |
| |
| static std::map<VABufferID, FakeBuffer> fake_buffer_map_; |
| static VABufferID next_buffer_id_; |
| |
| void vaCreateConfigStubSetReturn(VAStatus status) { vaCreateConfigReturn = status; } |
| |
| void vaCreateContextStubSetReturn(VAStatus status) { vaCreateContextReturn = status; } |
| |
| void vaCreateSurfacesStubSetReturn(VAStatus status) { vaCreateSurfacesReturn = status; } |
| |
| int vaMaxNumEntrypoints(VADisplay dpy) { return 2; } |
| VAStatus vaQueryConfigEntrypoints(VADisplay dpy, VAProfile profile, VAEntrypoint *entrypoint_list, |
| int *num_entrypoints) { |
| entrypoint_list[0] = VAEntrypointVLD; |
| entrypoint_list[1] = VAEntrypointEncSliceLP; |
| *num_entrypoints = 2; |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaGetConfigAttributes(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, |
| VAConfigAttrib *attrib_list, int num_attribs) { |
| EXPECT_EQ(1, num_attribs); |
| uint32_t &value = attrib_list[0].value; |
| switch (attrib_list[0].type) { |
| case VAConfigAttribRTFormat: |
| value = VA_RT_FORMAT_YUV420; |
| break; |
| case VAConfigAttribEncPackedHeaders: |
| value = |
| VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE | VA_ENC_PACKED_HEADER_SLICE; |
| break; |
| case VAConfigAttribEncMaxRefFrames: |
| value = 1; |
| break; |
| default: |
| EXPECT_TRUE(false) << "Unexpected attrib type " << attrib_list[0].type; |
| break; |
| } |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaDestroyConfig(VADisplay dpy, VAConfigID config_id) { |
| return VA_STATUS_ERROR_FLAG_NOT_SUPPORTED; |
| } |
| VAStatus vaCreateConfig(VADisplay dpy, VAProfile profile, VAEntrypoint entrypoint, |
| VAConfigAttrib *attrib_list, int num_attribs, VAConfigID *config_id) { |
| *config_id = 1; |
| return vaCreateConfigReturn; |
| } |
| int vaMaxNumConfigAttributes(VADisplay dpy) { return 6; } |
| VAStatus vaQueryConfigAttributes(VADisplay dpy, VAConfigID config_id, VAProfile *profile, |
| VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, |
| int *num_attribs) { |
| attrib_list[0].type = VAConfigAttribMaxPictureHeight; |
| attrib_list[0].value = 3840; |
| attrib_list[1].type = VAConfigAttribMaxPictureWidth; |
| attrib_list[1].value = 2160; |
| *num_attribs = 2; |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaQuerySurfaceAttributes(VADisplay dpy, VAConfigID config, VASurfaceAttrib *attrib_list, |
| unsigned int *num_attribs) { |
| if (attrib_list != nullptr) { |
| attrib_list[0] = {.type = VASurfaceAttribMinWidth, .value = {.value = {.i = 16}}}; |
| attrib_list[1] = {.type = VASurfaceAttribMaxWidth, .value = {.value = {.i = 3840}}}; |
| attrib_list[2] = {.type = VASurfaceAttribMinHeight, .value = {.value = {.i = 16}}}; |
| attrib_list[3] = {.type = VASurfaceAttribMaxHeight, .value = {.value = {.i = 2160}}}; |
| } |
| |
| *num_attribs = 4; |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaCreateSurfaces(VADisplay dpy, unsigned int format, unsigned int width, |
| unsigned int height, VASurfaceID *surfaces, unsigned int num_surfaces, |
| VASurfaceAttrib *attrib_list, unsigned int num_attribs) { |
| // User set return values take precedent |
| if (vaCreateSurfacesReturn != VA_STATUS_SUCCESS) { |
| return vaCreateSurfacesReturn; |
| } |
| |
| if (vaFreeSurfaces.size() < num_surfaces) { |
| return VA_STATUS_ERROR_MAX_NUM_EXCEEDED; |
| } |
| |
| for (size_t i = 0; i < num_surfaces; i++) { |
| surfaces[i] = *vaFreeSurfaces.begin(); |
| vaFreeSurfaces.erase(vaFreeSurfaces.begin()); |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaDestroySurfaces(VADisplay dpy, VASurfaceID *surfaces, int num_surfaces) { |
| for (int surface_idx = 0; surface_idx < num_surfaces; surface_idx += 1) { |
| if (vaFreeSurfaces.count(surfaces[surface_idx]) != 0) { |
| return VA_STATUS_ERROR_INVALID_SURFACE; |
| } |
| } |
| |
| for (int surface_idx = 0; surface_idx < num_surfaces; surface_idx += 1) { |
| vaFreeSurfaces.insert(surfaces[surface_idx]); |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaCreateContext(VADisplay dpy, VAConfigID config_id, int picture_width, int picture_height, |
| int flag, VASurfaceID *render_targets, int num_render_targets, |
| VAContextID *context) { |
| *context = 1; |
| return vaCreateContextReturn; |
| } |
| VAStatus vaDestroyContext(VADisplay dpy, VAContextID context) { return VA_STATUS_SUCCESS; } |
| VAStatus vaBeginPicture(VADisplay dpy, VAContextID context, VASurfaceID render_target) { |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaRenderPicture(VADisplay dpy, VAContextID context, VABufferID *buffers, int num_buffers) { |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaEndPicture(VADisplay dpy, VAContextID context) { return VA_STATUS_SUCCESS; } |
| VAStatus vaSyncSurface(VADisplay dpy, VASurfaceID render_target) { return VA_STATUS_SUCCESS; } |
| // If the vaSyncSurface stub ever returns VA_STATUS_ERROR_DECODING_ERROR, this stub should be |
| // updated since the client will query why vaSyncSurface failed |
| VAStatus vaQuerySurfaceError(VADisplay dpy, VASurfaceID surface, VAStatus error_status, |
| void **error_info) { |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaGetImage(VADisplay dpy, VASurfaceID surface, int x, int y, unsigned int width, |
| unsigned int height, VAImageID image) { |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaDeriveImage(VADisplay dpy, VASurfaceID surface, VAImage *image) { |
| // Arbitrary dimensions that match those in the H264 Encoder tests. |
| constexpr uint32_t kImageBufferSize = 12 * 12 * 3 / 2; |
| fake_buffer_map_[next_buffer_id_].size = kImageBufferSize; |
| image->buf = next_buffer_id_++; |
| image->offsets[0] = 0; |
| image->pitches[0] = 10; |
| image->offsets[1] = 10 * 10; |
| image->pitches[1] = 10; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaDestroyImage(VADisplay dpy, VAImageID image) { return VA_STATUS_SUCCESS; } |
| |
| VAStatus vaCreateBuffer(VADisplay dpy, VAContextID context, VABufferType type, unsigned int size, |
| unsigned int num_elements, void *data, VABufferID *buf_id) { |
| FakeBuffer &fake_buffer = fake_buffer_map_[next_buffer_id_]; |
| fake_buffer.size = size; |
| fake_buffer.type = type; |
| *buf_id = next_buffer_id_++; |
| |
| return VA_STATUS_SUCCESS; |
| } |
| VAStatus vaDestroyBuffer(VADisplay dpy, VABufferID buffer_id) { |
| fake_buffer_map_.erase(buffer_id); |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaInitialize(VADisplay dpy, int *major_version, int *minor_version) { |
| *major_version = VA_MAJOR_VERSION; |
| *minor_version = VA_MINOR_VERSION; |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaMapBuffer(VADisplay dpy, VABufferID buf_id, void **pbuf) { |
| FakeBuffer &buf = fake_buffer_map_[buf_id]; |
| buf.mapped_buffer = std::make_unique<std::vector<uint8_t>>(buf.size); |
| |
| if (buf.type == VAEncCodedBufferType) { |
| buf.coded_segment = std::make_unique<VACodedBufferSegment>(); |
| *pbuf = buf.coded_segment.get(); |
| buf.coded_segment->size = 10; |
| buf.coded_segment->buf = buf.mapped_buffer->data(); |
| buf.coded_segment->next = nullptr; |
| } else { |
| *pbuf = buf.mapped_buffer->data(); |
| } |
| |
| return VA_STATUS_SUCCESS; |
| } |
| |
| VAStatus vaUnmapBuffer(VADisplay dpy, VABufferID buf_id) { return VA_STATUS_SUCCESS; } |
| |
| const char *vaErrorStr(VAStatus error_status) { |
| switch (error_status) { |
| case VA_STATUS_SUCCESS: |
| return "success (no error)"; |
| case VA_STATUS_ERROR_OPERATION_FAILED: |
| return "operation failed"; |
| case VA_STATUS_ERROR_ALLOCATION_FAILED: |
| return "resource allocation failed"; |
| case VA_STATUS_ERROR_INVALID_DISPLAY: |
| return "invalid VADisplay"; |
| case VA_STATUS_ERROR_INVALID_CONFIG: |
| return "invalid VAConfigID"; |
| case VA_STATUS_ERROR_INVALID_CONTEXT: |
| return "invalid VAContextID"; |
| case VA_STATUS_ERROR_INVALID_SURFACE: |
| return "invalid VASurfaceID"; |
| case VA_STATUS_ERROR_INVALID_BUFFER: |
| return "invalid VABufferID"; |
| case VA_STATUS_ERROR_INVALID_IMAGE: |
| return "invalid VAImageID"; |
| case VA_STATUS_ERROR_INVALID_SUBPICTURE: |
| return "invalid VASubpictureID"; |
| case VA_STATUS_ERROR_ATTR_NOT_SUPPORTED: |
| return "attribute not supported"; |
| case VA_STATUS_ERROR_MAX_NUM_EXCEEDED: |
| return "list argument exceeds maximum number"; |
| case VA_STATUS_ERROR_UNSUPPORTED_PROFILE: |
| return "the requested VAProfile is not supported"; |
| case VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT: |
| return "the requested VAEntryPoint is not supported"; |
| case VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT: |
| return "the requested RT Format is not supported"; |
| case VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE: |
| return "the requested VABufferType is not supported"; |
| case VA_STATUS_ERROR_SURFACE_BUSY: |
| return "surface is in use"; |
| case VA_STATUS_ERROR_FLAG_NOT_SUPPORTED: |
| return "flag not supported"; |
| case VA_STATUS_ERROR_INVALID_PARAMETER: |
| return "invalid parameter"; |
| case VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED: |
| return "resolution not supported"; |
| case VA_STATUS_ERROR_UNIMPLEMENTED: |
| return "the requested function is not implemented"; |
| case VA_STATUS_ERROR_SURFACE_IN_DISPLAYING: |
| return "surface is in displaying (may by overlay)"; |
| case VA_STATUS_ERROR_INVALID_IMAGE_FORMAT: |
| return "invalid VAImageFormat"; |
| case VA_STATUS_ERROR_DECODING_ERROR: |
| return "internal decoding error"; |
| case VA_STATUS_ERROR_ENCODING_ERROR: |
| return "internal encoding error"; |
| case VA_STATUS_ERROR_INVALID_VALUE: |
| return "an invalid/unsupported value was supplied"; |
| case VA_STATUS_ERROR_UNSUPPORTED_FILTER: |
| return "the requested filter is not supported"; |
| case VA_STATUS_ERROR_INVALID_FILTER_CHAIN: |
| return "an invalid filter chain was supplied"; |
| case VA_STATUS_ERROR_HW_BUSY: |
| return "HW busy now"; |
| case VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE: |
| return "an unsupported memory type was supplied"; |
| case VA_STATUS_ERROR_NOT_ENOUGH_BUFFER: |
| return "allocated memory size is not enough for input or output"; |
| } |
| return "unknown libva error / description missing"; |
| } |
| |
| VADisplay vaGetDisplayMagma(magma_device_t device) { return &vaGetDisplayMagmaReturn; } |
| |
| VAMessageCallback vaSetErrorCallback(VADisplay dpy, VAMessageCallback callback, |
| void *user_context) { |
| return nullptr; |
| } |
| |
| VAMessageCallback vaSetInfoCallback(VADisplay dpy, VAMessageCallback callback, void *user_context) { |
| return nullptr; |
| } |