blob: c42f7bce24451bde1b9aef2cae424adc3e8b8015 [file] [log] [blame]
Greg Daniel94403452017-04-18 15:52:36 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrBackendSurface_DEFINED
9#define GrBackendSurface_DEFINED
10
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrTypes.h"
12#include "include/gpu/gl/GrGLTypes.h"
13#include "include/gpu/mock/GrMockTypes.h"
14#include "include/gpu/vk/GrVkTypes.h"
15#include "include/private/GrVkTypesPriv.h"
Greg Daniel52e16d92018-04-10 09:34:07 -040016
17class GrVkImageLayout;
Greg Daniel94403452017-04-18 15:52:36 -040018
Timothy Liang4e85e802018-06-28 16:37:18 -040019#ifdef SK_METAL
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/gpu/mtl/GrMtlTypes.h"
Timothy Liang4e85e802018-06-28 16:37:18 -040021#endif
22
Robert Phillips8caf85f2018-04-05 09:30:38 -040023#if !SK_SUPPORT_GPU
24
25// SkSurface and SkImage rely on a minimal version of these always being available
26class SK_API GrBackendTexture {
27public:
28 GrBackendTexture() {}
29
30 bool isValid() const { return false; }
31};
32
33class SK_API GrBackendRenderTarget {
34public:
35 GrBackendRenderTarget() {}
36
37 bool isValid() const { return false; }
38};
39#else
40
Robert Phillipsfc711a22018-02-13 17:03:00 -050041class SK_API GrBackendFormat {
42public:
43 // Creates an invalid backend format.
44 GrBackendFormat() : fValid(false) {}
45
46 static GrBackendFormat MakeGL(GrGLenum format, GrGLenum target) {
47 return GrBackendFormat(format, target);
48 }
49
Greg Daniela8d92112018-03-09 12:05:04 -050050 static GrBackendFormat MakeVk(VkFormat format) {
Greg Daniel7e000222018-12-03 10:08:21 -050051 return GrBackendFormat(format, GrVkYcbcrConversionInfo());
Robert Phillipsfc711a22018-02-13 17:03:00 -050052 }
Robert Phillipsfc711a22018-02-13 17:03:00 -050053
Greg Daniel7e000222018-12-03 10:08:21 -050054 // This is used for external textures and the VkFormat is assumed to be VK_FORMAT_UNDEFINED.
55 // This call is only supported on Android since the GrVkYcbcrConvesionInfo contains an android
56 // external format.
57 static GrBackendFormat MakeVk(const GrVkYcbcrConversionInfo& ycbcrInfo);
58
Timothy Liang4e85e802018-06-28 16:37:18 -040059#ifdef SK_METAL
60 static GrBackendFormat MakeMtl(GrMTLPixelFormat format) {
61 return GrBackendFormat(format);
62 }
63#endif
64
Robert Phillipsfc711a22018-02-13 17:03:00 -050065 static GrBackendFormat MakeMock(GrPixelConfig config) {
66 return GrBackendFormat(config);
67 }
68
Greg Daniel45723ac2018-11-30 10:12:43 -050069 bool operator==(const GrBackendFormat& that) const;
70 bool operator!=(const GrBackendFormat& that) const { return !(*this == that); }
71
Greg Daniel4065d452018-11-16 15:43:41 -050072 GrBackendApi backend() const { return fBackend; }
73 GrTextureType textureType() const { return fTextureType; }
Robert Phillipsfc711a22018-02-13 17:03:00 -050074
75 // If the backend API is GL, these return a pointer to the format and target. Otherwise
76 // it returns nullptr.
77 const GrGLenum* getGLFormat() const;
78 const GrGLenum* getGLTarget() const;
79
Robert Phillipsfc711a22018-02-13 17:03:00 -050080 // If the backend API is Vulkan, this returns a pointer to a VkFormat. Otherwise
81 // it returns nullptr
82 const VkFormat* getVkFormat() const;
Robert Phillipsfc711a22018-02-13 17:03:00 -050083
Greg Daniel7e000222018-12-03 10:08:21 -050084 const GrVkYcbcrConversionInfo* getVkYcbcrConversionInfo() const;
85
Timothy Liang4e85e802018-06-28 16:37:18 -040086#ifdef SK_METAL
87 // If the backend API is Metal, this returns a pointer to a GrMTLPixelFormat. Otherwise
88 // it returns nullptr
89 const GrMTLPixelFormat* getMtlFormat() const;
90#endif
91
Robert Phillipsfc711a22018-02-13 17:03:00 -050092 // If the backend API is Mock, this returns a pointer to a GrPixelConfig. Otherwise
93 // it returns nullptr.
94 const GrPixelConfig* getMockFormat() const;
95
Greg Daniel387ec9a2019-03-07 16:44:54 -050096 // If possible, copies the GrBackendFormat and forces the texture type to be Texture2D. If the
97 // GrBackendFormat was for Vulkan and it originally had a GrVkYcbcrConversionInfo, we will
98 // remove the conversion and set the format to be VK_FORMAT_R8G8B8A8_UNORM.
Greg Daniel4065d452018-11-16 15:43:41 -050099 GrBackendFormat makeTexture2D() const;
100
Robert Phillipsfc711a22018-02-13 17:03:00 -0500101 // Returns true if the backend format has been initialized.
102 bool isValid() const { return fValid; }
103
104private:
105 GrBackendFormat(GrGLenum format, GrGLenum target);
106
Greg Daniel7e000222018-12-03 10:08:21 -0500107 GrBackendFormat(const VkFormat vkFormat, const GrVkYcbcrConversionInfo&);
Robert Phillipsfc711a22018-02-13 17:03:00 -0500108
Timothy Liang4e85e802018-06-28 16:37:18 -0400109#ifdef SK_METAL
110 GrBackendFormat(const GrMTLPixelFormat mtlFormat);
111#endif
112
Robert Phillipsfc711a22018-02-13 17:03:00 -0500113 GrBackendFormat(const GrPixelConfig config);
114
Greg Danielbdf12ad2018-10-12 09:31:11 -0400115 GrBackendApi fBackend;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400116 bool fValid;
Robert Phillipsfc711a22018-02-13 17:03:00 -0500117
118 union {
Greg Daniel4065d452018-11-16 15:43:41 -0500119 GrGLenum fGLFormat; // the sized, internal format of the GL resource
Greg Daniel7e000222018-12-03 10:08:21 -0500120 struct {
121 VkFormat fFormat;
122 GrVkYcbcrConversionInfo fYcbcrConversionInfo;
Robert Phillips9dbcdcc2019-05-13 10:40:06 -0400123 } fVk;
Timothy Liang4e85e802018-06-28 16:37:18 -0400124#ifdef SK_METAL
125 GrMTLPixelFormat fMtlFormat;
126#endif
127 GrPixelConfig fMockFormat;
Robert Phillipsfc711a22018-02-13 17:03:00 -0500128 };
Greg Daniel4065d452018-11-16 15:43:41 -0500129 GrTextureType fTextureType;
Robert Phillipsfc711a22018-02-13 17:03:00 -0500130};
131
Brian Salomonec045b42017-07-07 10:34:40 -0400132class SK_API GrBackendTexture {
Greg Daniel94403452017-04-18 15:52:36 -0400133public:
Brian Salomon8fe24272017-07-07 12:56:11 -0400134 // Creates an invalid backend texture.
Greg Daniel9ca30652018-04-06 09:27:20 -0400135 GrBackendTexture() : fIsValid(false) {}
Brian Salomon8fe24272017-07-07 12:56:11 -0400136
Greg Daniele7d8da42017-12-04 11:23:19 -0500137 // The GrGLTextureInfo must have a valid fFormat.
138 GrBackendTexture(int width,
139 int height,
140 GrMipMapped,
141 const GrGLTextureInfo& glInfo);
142
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000143 GrBackendTexture(int width,
144 int height,
145 const GrVkImageInfo& vkInfo);
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000146
Timothy Liang4e85e802018-06-28 16:37:18 -0400147#ifdef SK_METAL
148 GrBackendTexture(int width,
149 int height,
150 GrMipMapped,
151 const GrMtlTextureInfo& mtlInfo);
152#endif
153
Brian Salomon8fe24272017-07-07 12:56:11 -0400154 GrBackendTexture(int width,
155 int height,
Greg Daniel177e6952017-10-12 12:27:11 -0400156 GrMipMapped,
157 const GrMockTextureInfo& mockInfo);
158
Greg Daniel52e16d92018-04-10 09:34:07 -0400159 GrBackendTexture(const GrBackendTexture& that);
160
161 ~GrBackendTexture();
162
163 GrBackendTexture& operator=(const GrBackendTexture& that);
164
Greg Daniel94403452017-04-18 15:52:36 -0400165 int width() const { return fWidth; }
166 int height() const { return fHeight; }
Greg Daniel177e6952017-10-12 12:27:11 -0400167 bool hasMipMaps() const { return GrMipMapped::kYes == fMipMapped; }
Greg Danielbdf12ad2018-10-12 09:31:11 -0400168 GrBackendApi backend() const {return fBackend; }
Greg Daniel94403452017-04-18 15:52:36 -0400169
Greg Daniel52e16d92018-04-10 09:34:07 -0400170 // If the backend API is GL, copies a snapshot of the GrGLTextureInfo struct into the passed in
171 // pointer and returns true. Otherwise returns false if the backend API is not GL.
172 bool getGLTextureInfo(GrGLTextureInfo*) const;
Greg Danielc0f8e422017-06-13 13:47:53 -0400173
Greg Daniel323fbcf2018-04-10 13:46:30 -0400174 // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed
Greg Daniel52e16d92018-04-10 09:34:07 -0400175 // in pointer and returns true. This snapshot will set the fImageLayout to the current layout
176 // state. Otherwise returns false if the backend API is not Vulkan.
177 bool getVkImageInfo(GrVkImageInfo*) const;
178
Greg Daniel323fbcf2018-04-10 13:46:30 -0400179 // Anytime the client changes the VkImageLayout of the VkImage captured by this
180 // GrBackendTexture, they must call this function to notify Skia of the changed layout.
Greg Daniel52e16d92018-04-10 09:34:07 -0400181 void setVkImageLayout(VkImageLayout);
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000182
Timothy Liang4e85e802018-06-28 16:37:18 -0400183#ifdef SK_METAL
184 // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed
185 // in pointer and returns true. Otherwise returns false if the backend API is not Metal.
186 bool getMtlTextureInfo(GrMtlTextureInfo*) const;
187#endif
188
Brian Salomonf391d0f2018-12-14 09:18:50 -0500189 // Get the GrBackendFormat for this texture (or an invalid format if this is not valid).
190 GrBackendFormat getBackendFormat() const;
191
Greg Daniel52e16d92018-04-10 09:34:07 -0400192 // If the backend API is Mock, copies a snapshot of the GrMockTextureInfo struct into the passed
193 // in pointer and returns true. Otherwise returns false if the backend API is not Mock.
194 bool getMockTextureInfo(GrMockTextureInfo*) const;
Brian Salomon8fe24272017-07-07 12:56:11 -0400195
Eric Karl914a36b2017-10-12 12:44:50 -0700196 // Returns true if the backend texture has been initialized.
Greg Daniel9ca30652018-04-06 09:27:20 -0400197 bool isValid() const { return fIsValid; }
Brian Salomon8fe24272017-07-07 12:56:11 -0400198
Brian Salomonaad83152019-05-24 10:16:35 -0400199 // Returns true if both textures are valid and refer to the same API texture.
200 bool isSameTexture(const GrBackendTexture&);
201
Robert Phillipsc5509952018-04-04 15:54:55 -0400202#if GR_TEST_UTILS
Greg Daniel108bb232018-07-03 16:18:29 -0400203 // We can remove the pixelConfig getter and setter once we remove the GrPixelConfig from the
204 // GrBackendTexture and plumb the GrPixelconfig manually throughout our code (or remove all use
205 // of GrPixelConfig in general).
206 GrPixelConfig pixelConfig() const { return fConfig; }
207 void setPixelConfig(GrPixelConfig config) { fConfig = config; }
208
Robert Phillipsc5509952018-04-04 15:54:55 -0400209 static bool TestingOnly_Equals(const GrBackendTexture& , const GrBackendTexture&);
210#endif
Greg Daniel2a303902018-02-20 10:25:54 -0500211
Eric Karl914a36b2017-10-12 12:44:50 -0700212private:
Greg Daniel5254ccc2017-11-13 11:05:52 -0500213 // Friending for access to the GrPixelConfig
Greg Danielfaa095e2017-12-19 13:15:02 -0500214 friend class SkImage;
Brian Salomon6a426c12018-03-15 12:16:02 -0400215 friend class SkImage_Gpu;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400216 friend class SkImage_GpuBase;
Jim Van Verthf49262d2018-10-02 12:07:20 -0400217 friend class SkImage_GpuYUVA;
Jim Van Verth8bbce0e2018-10-08 14:34:52 -0400218 friend class SkPromiseImageHelper;
Greg Daniel5254ccc2017-11-13 11:05:52 -0500219 friend class SkSurface;
Brian Salomonaad83152019-05-24 10:16:35 -0400220 friend class SkSurface_Gpu;
Greg Daniel108bb232018-07-03 16:18:29 -0400221 friend class GrAHardwareBufferImageGenerator;
Greg Daniele728f672018-01-17 10:52:04 -0500222 friend class GrBackendTextureImageGenerator;
Greg Danielf2336e42018-01-23 16:38:14 -0500223 friend class GrProxyProvider;
Greg Daniel5254ccc2017-11-13 11:05:52 -0500224 friend class GrGpu;
225 friend class GrGLGpu;
226 friend class GrVkGpu;
Timothy Liang4e85e802018-06-28 16:37:18 -0400227 friend class GrMtlGpu;
Greg Daniel057627f2018-03-14 15:51:58 -0400228 friend class PromiseImageHelper;
Robert Phillipsc5509952018-04-04 15:54:55 -0400229
Greg Daniel5254ccc2017-11-13 11:05:52 -0500230 GrPixelConfig config() const { return fConfig; }
231
Greg Daniel52e16d92018-04-10 09:34:07 -0400232 // Requires friending of GrVkGpu (done above already)
233 sk_sp<GrVkImageLayout> getGrVkImageLayout() const;
234
235 friend class GrVkTexture;
Greg Danielb4d89562018-10-03 18:44:49 +0000236#ifdef SK_VULKAN
Greg Daniel52e16d92018-04-10 09:34:07 -0400237 GrBackendTexture(int width,
238 int height,
239 const GrVkImageInfo& vkInfo,
240 sk_sp<GrVkImageLayout> layout);
241#endif
242
243 // Free and release and resources being held by the GrBackendTexture.
244 void cleanup();
245
Greg Daniel9ca30652018-04-06 09:27:20 -0400246 bool fIsValid;
Greg Daniel94403452017-04-18 15:52:36 -0400247 int fWidth; //<! width in pixels
248 int fHeight; //<! height in pixels
249 GrPixelConfig fConfig;
Greg Daniel177e6952017-10-12 12:27:11 -0400250 GrMipMapped fMipMapped;
Greg Danielbdf12ad2018-10-12 09:31:11 -0400251 GrBackendApi fBackend;
Greg Daniel94403452017-04-18 15:52:36 -0400252
253 union {
Robert Phillipsfad9e3f2017-06-13 22:16:08 +0000254 GrGLTextureInfo fGLInfo;
Greg Daniel52e16d92018-04-10 09:34:07 -0400255 GrVkBackendSurfaceInfo fVkInfo;
Timothy Liang4e85e802018-06-28 16:37:18 -0400256#ifdef SK_METAL
257 GrMtlTextureInfo fMtlInfo;
258#endif
Brian Salomon8fe24272017-07-07 12:56:11 -0400259 GrMockTextureInfo fMockInfo;
Greg Daniel94403452017-04-18 15:52:36 -0400260 };
261};
262
Brian Salomonec045b42017-07-07 10:34:40 -0400263class SK_API GrBackendRenderTarget {
Greg Daniel94403452017-04-18 15:52:36 -0400264public:
Robert Phillips57e08282017-11-16 14:59:48 -0500265 // Creates an invalid backend texture.
Greg Daniel9ca30652018-04-06 09:27:20 -0400266 GrBackendRenderTarget() : fIsValid(false) {}
Robert Phillips57e08282017-11-16 14:59:48 -0500267
Greg Danielfaa095e2017-12-19 13:15:02 -0500268 // The GrGLTextureInfo must have a valid fFormat.
269 GrBackendRenderTarget(int width,
270 int height,
271 int sampleCnt,
272 int stencilBits,
273 const GrGLFramebufferInfo& glInfo);
274
Brian Salomonafdc6b12018-03-09 12:02:32 -0500275 /** Deprecated, use version that does not take stencil bits. */
Greg Daniel94403452017-04-18 15:52:36 -0400276 GrBackendRenderTarget(int width,
277 int height,
278 int sampleCnt,
279 int stencilBits,
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000280 const GrVkImageInfo& vkInfo);
Brian Salomonafdc6b12018-03-09 12:02:32 -0500281 GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo);
Greg Daniel94403452017-04-18 15:52:36 -0400282
Timothy Liang4e85e802018-06-28 16:37:18 -0400283#ifdef SK_METAL
284 GrBackendRenderTarget(int width,
285 int height,
286 int sampleCnt,
287 const GrMtlTextureInfo& mtlInfo);
288#endif
289
Brian Salomon0c51eea2018-03-09 17:02:09 -0500290 GrBackendRenderTarget(int width,
291 int height,
292 int sampleCnt,
293 int stencilBits,
294 const GrMockRenderTargetInfo& mockInfo);
295
Greg Daniel323fbcf2018-04-10 13:46:30 -0400296 ~GrBackendRenderTarget();
297
298 GrBackendRenderTarget(const GrBackendRenderTarget& that);
299 GrBackendRenderTarget& operator=(const GrBackendRenderTarget&);
300
Greg Daniel94403452017-04-18 15:52:36 -0400301 int width() const { return fWidth; }
302 int height() const { return fHeight; }
303 int sampleCnt() const { return fSampleCnt; }
304 int stencilBits() const { return fStencilBits; }
Greg Danielbdf12ad2018-10-12 09:31:11 -0400305 GrBackendApi backend() const {return fBackend; }
Greg Daniel94403452017-04-18 15:52:36 -0400306
Greg Daniel323fbcf2018-04-10 13:46:30 -0400307 // If the backend API is GL, copies a snapshot of the GrGLFramebufferInfo struct into the passed
308 // in pointer and returns true. Otherwise returns false if the backend API is not GL.
309 bool getGLFramebufferInfo(GrGLFramebufferInfo*) const;
Greg Danielc0f8e422017-06-13 13:47:53 -0400310
Greg Daniel323fbcf2018-04-10 13:46:30 -0400311 // If the backend API is Vulkan, copies a snapshot of the GrVkImageInfo struct into the passed
312 // in pointer and returns true. This snapshot will set the fImageLayout to the current layout
313 // state. Otherwise returns false if the backend API is not Vulkan.
314 bool getVkImageInfo(GrVkImageInfo*) const;
315
316 // Anytime the client changes the VkImageLayout of the VkImage captured by this
317 // GrBackendRenderTarget, they must call this function to notify Skia of the changed layout.
318 void setVkImageLayout(VkImageLayout);
Robert Phillipsfcd5fdd2017-06-14 01:43:29 +0000319
Timothy Liang4e85e802018-06-28 16:37:18 -0400320#ifdef SK_METAL
321 // If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed
322 // in pointer and returns true. Otherwise returns false if the backend API is not Metal.
323 bool getMtlTextureInfo(GrMtlTextureInfo*) const;
324#endif
325
Greg Daniel323fbcf2018-04-10 13:46:30 -0400326 // If the backend API is Mock, copies a snapshot of the GrMockTextureInfo struct into the passed
327 // in pointer and returns true. Otherwise returns false if the backend API is not Mock.
328 bool getMockRenderTargetInfo(GrMockRenderTargetInfo*) const;
Brian Salomon0c51eea2018-03-09 17:02:09 -0500329
Robert Phillips57e08282017-11-16 14:59:48 -0500330 // Returns true if the backend texture has been initialized.
Greg Daniel9ca30652018-04-06 09:27:20 -0400331 bool isValid() const { return fIsValid; }
Robert Phillips57e08282017-11-16 14:59:48 -0500332
Robert Phillips8caf85f2018-04-05 09:30:38 -0400333
334#if GR_TEST_UTILS
Greg Daniel108bb232018-07-03 16:18:29 -0400335 // We can remove the pixelConfig getter and setter once we remove the pixel config from the
336 // GrBackendRenderTarget and plumb the pixel config manually throughout our code (or remove all
337 // use of GrPixelConfig in general).
338 GrPixelConfig pixelConfig() const { return fConfig; }
339 void setPixelConfig(GrPixelConfig config) { fConfig = config; }
340
Robert Phillips8caf85f2018-04-05 09:30:38 -0400341 static bool TestingOnly_Equals(const GrBackendRenderTarget&, const GrBackendRenderTarget&);
342#endif
Greg Daniel2a303902018-02-20 10:25:54 -0500343
Greg Daniel94403452017-04-18 15:52:36 -0400344private:
Greg Daniel5254ccc2017-11-13 11:05:52 -0500345 // Friending for access to the GrPixelConfig
346 friend class SkSurface;
Greg Danielfaa095e2017-12-19 13:15:02 -0500347 friend class SkSurface_Gpu;
348 friend class SkImage_Gpu;
Greg Daniel5254ccc2017-11-13 11:05:52 -0500349 friend class GrGpu;
350 friend class GrGLGpu;
Greg Daniel2a303902018-02-20 10:25:54 -0500351 friend class GrProxyProvider;
Greg Daniel5254ccc2017-11-13 11:05:52 -0500352 friend class GrVkGpu;
Timothy Liang4e85e802018-06-28 16:37:18 -0400353 friend class GrMtlGpu;
Greg Daniel5254ccc2017-11-13 11:05:52 -0500354 GrPixelConfig config() const { return fConfig; }
355
Greg Daniel323fbcf2018-04-10 13:46:30 -0400356 // Requires friending of GrVkGpu (done above already)
357 sk_sp<GrVkImageLayout> getGrVkImageLayout() const;
358
359 friend class GrVkRenderTarget;
360 GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo,
361 sk_sp<GrVkImageLayout> layout);
Greg Daniel323fbcf2018-04-10 13:46:30 -0400362
363 // Free and release and resources being held by the GrBackendTexture.
364 void cleanup();
365
Greg Daniel9ca30652018-04-06 09:27:20 -0400366 bool fIsValid;
Greg Daniel94403452017-04-18 15:52:36 -0400367 int fWidth; //<! width in pixels
368 int fHeight; //<! height in pixels
369
370 int fSampleCnt;
371 int fStencilBits;
372 GrPixelConfig fConfig;
373
Greg Danielbdf12ad2018-10-12 09:31:11 -0400374 GrBackendApi fBackend;
Greg Daniel94403452017-04-18 15:52:36 -0400375
376 union {
Robert Phillipsfad9e3f2017-06-13 22:16:08 +0000377 GrGLFramebufferInfo fGLInfo;
Greg Daniel323fbcf2018-04-10 13:46:30 -0400378 GrVkBackendSurfaceInfo fVkInfo;
Timothy Liang4e85e802018-06-28 16:37:18 -0400379#ifdef SK_METAL
380 GrMtlTextureInfo fMtlInfo;
381#endif
Brian Salomon0c51eea2018-03-09 17:02:09 -0500382 GrMockRenderTargetInfo fMockInfo;
Greg Daniel94403452017-04-18 15:52:36 -0400383 };
384};
385
386#endif
387
Robert Phillips8caf85f2018-04-05 09:30:38 -0400388#endif
389